ghost 5.4.1 → 5.7.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/PRIVACY.md +3 -2
- package/components/tryghost-adapter-manager-0.0.0.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-0.0.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-0.0.0.tgz +0 -0
- package/components/tryghost-constants-0.0.0.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-0.0.0.tgz +0 -0
- package/components/tryghost-domain-events-0.0.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-0.0.0.tgz +0 -0
- package/components/tryghost-email-analytics-service-0.0.0.tgz +0 -0
- package/components/tryghost-email-content-generator-0.0.0.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-0.0.0.tgz +0 -0
- package/components/tryghost-extract-api-key-0.0.0.tgz +0 -0
- package/components/tryghost-job-manager-0.0.0.tgz +0 -0
- package/components/tryghost-magic-link-0.0.0.tgz +0 -0
- package/components/tryghost-member-analytics-service-0.0.0.tgz +0 -0
- package/components/tryghost-member-events-0.0.0.tgz +0 -0
- package/components/tryghost-members-analytics-ingress-0.0.0.tgz +0 -0
- package/components/tryghost-members-api-0.0.0.tgz +0 -0
- package/components/tryghost-members-csv-0.0.0.tgz +0 -0
- package/components/tryghost-members-events-service-0.0.0.tgz +0 -0
- package/components/tryghost-members-importer-0.0.0.tgz +0 -0
- package/components/tryghost-members-offers-0.0.0.tgz +0 -0
- package/components/tryghost-members-payments-0.0.0.tgz +0 -0
- package/components/tryghost-members-ssr-0.0.0.tgz +0 -0
- package/components/tryghost-members-stripe-service-0.0.0.tgz +0 -0
- package/components/tryghost-minifier-0.0.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-0.0.0.tgz +0 -0
- package/components/tryghost-mw-error-handler-0.0.0.tgz +0 -0
- package/components/tryghost-mw-session-from-token-0.0.0.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-0.0.0.tgz +0 -0
- package/components/tryghost-mw-vhost-0.0.0.tgz +0 -0
- package/components/tryghost-package-json-0.0.0.tgz +0 -0
- package/components/tryghost-security-0.0.0.tgz +0 -0
- package/components/tryghost-session-service-0.0.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-0.0.0.tgz +0 -0
- package/components/tryghost-update-check-service-0.0.0.tgz +0 -0
- package/components/tryghost-verification-trigger-0.0.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-0.0.0.tgz +0 -0
- package/content/themes/casper/assets/built/global.css +1 -1
- package/content/themes/casper/assets/built/global.css.map +1 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/screen.css +9 -1
- package/content/themes/casper/gulpfile.js +1 -1
- package/content/themes/casper/package.json +9 -9
- package/content/themes/casper/yarn.lock +1154 -1249
- package/core/boot.js +6 -1
- package/core/built/assets/{chunk.3.dc389a0f93cb5fabd695.js → chunk.3.33097bb5eb150719bdd2.js} +19 -19
- package/core/built/assets/fonts/Inter.ttf +0 -0
- package/core/built/assets/ghost-dark-1bdd57aba1fa4a23388121740454dab2.css +1 -0
- package/core/built/assets/ghost.min-8f5c061e0892b93adecc2b9e37ad2f3a.css +1 -0
- package/core/built/assets/{ghost.min-36b64813b14c45075770658269d4b478.js → ghost.min-ff9ba089fd81cb40831f4b62e63a2ca9.js} +3015 -2874
- package/core/built/assets/icons/event-comment.svg +3 -0
- package/core/built/assets/{vendor.min-be0129c9c6897c9f10425e2402881d77.js → vendor.min-3dd40d3052381526f38fd290d13baa47.js} +2394 -924
- package/core/frontend/helpers/comments.js +39 -14
- package/core/frontend/helpers/ghost_head.js +22 -4
- package/core/frontend/helpers/img_url.js +67 -6
- package/core/frontend/utils/frontend-apps.js +33 -0
- package/core/frontend/web/middleware/handle-image-sizes.js +7 -11
- package/core/server/api/endpoints/{comments-comments.js → comments-members.js} +24 -43
- package/core/server/api/endpoints/index.js +2 -6
- package/core/server/api/endpoints/utils/serializers/output/config.js +2 -1
- package/core/server/api/endpoints/utils/serializers/output/mappers/activity-feed-events.js +17 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +18 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/index.js +1 -0
- package/core/server/api/endpoints/utils/serializers/output/mappers/posts.js +11 -0
- package/core/server/api/endpoints/utils/serializers/output/members.js +12 -1
- package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +4 -0
- package/core/server/data/exporter/table-lists.js +2 -1
- package/core/server/data/migrations/versions/5.3/2022-07-06-09-17-add-ghost-explore-integration.js +0 -1
- package/core/server/data/migrations/versions/5.3/2022-07-06-09-26-add-ghost-explore-integration-api-key.js +0 -1
- package/core/server/data/migrations/versions/5.5/2022-07-18-14-29-add-comment-reporting-permissions.js +10 -0
- package/core/server/data/migrations/versions/5.5/2022-07-18-14-31-drop-reports-reason.js +3 -0
- package/core/server/data/migrations/versions/5.5/2022-07-18-14-32-drop-nullable-member-id-from-likes.js +4 -0
- package/core/server/data/migrations/versions/5.5/2022-07-18-14-33-fix-comments-on-delete-foreign-keys.js +119 -0
- package/core/server/data/migrations/versions/5.5/2022-07-21-08-56-add-jobs-table.js +11 -0
- package/core/server/data/migrations/versions/5.6/2022-07-27-13-40-change-explore-type.js +24 -0
- package/core/server/data/schema/commands.js +7 -2
- package/core/server/data/schema/fixtures/fixtures.json +6 -1
- package/core/server/data/schema/schema.js +12 -4
- package/core/server/ghost-server.js +0 -22
- package/core/server/models/comment-report.js +34 -0
- package/core/server/models/comment.js +8 -7
- package/core/server/models/job.js +9 -0
- package/core/server/services/bulk-email/bulk-email-processor.js +6 -0
- package/core/server/services/comments/controller.js +82 -0
- package/core/server/services/comments/email-templates/new-comment-reply.hbs +2 -2
- package/core/server/services/comments/email-templates/new-comment-reply.txt.js +7 -8
- package/core/server/services/comments/email-templates/new-comment.hbs +2 -2
- package/core/server/services/comments/email-templates/new-comment.txt.js +7 -6
- package/core/server/services/comments/email-templates/report.hbs +199 -0
- package/core/server/services/comments/email-templates/report.txt.js +16 -0
- package/core/server/services/comments/emails.js +57 -1
- package/core/server/services/comments/index.js +6 -1
- package/core/server/services/comments/service.js +291 -9
- package/core/server/services/jobs/job-service.js +24 -1
- package/core/server/services/mail/GhostMailer.js +1 -0
- package/core/server/services/mega/email-preview.js +5 -1
- package/core/server/services/mega/mega.js +2 -4
- package/core/server/services/mega/post-email-serializer.js +97 -2
- package/core/server/services/mega/segment-parser.js +10 -1
- package/core/server/services/members/api.js +2 -1
- package/core/server/services/members/service.js +9 -4
- package/core/server/services/public-config/config.js +2 -1
- package/core/server/services/stripe/service.js +9 -1
- 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/testmode/jobs/graceful-job.js +2 -2
- package/core/server/web/api/testmode/routes.js +14 -0
- package/core/server/web/comments/routes.js +10 -8
- package/core/shared/config/defaults.json +12 -7
- package/core/shared/config/env/config.testing.json +3 -2
- package/core/shared/labs.js +5 -2
- package/package.json +92 -59
- package/yarn.lock +1821 -2011
- package/core/built/assets/ghost-dark-739c1f5546bd048eeeb253965ef36712.css +0 -1
- package/core/built/assets/ghost.min-5211776b9497f36fac8c9e5f2584cbcc.css +0 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const {addForeign, dropForeign} = require('../../../schema/commands');
|
|
2
|
+
const logging = require('@tryghost/logging');
|
|
3
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = createTransactionalMigration(
|
|
6
|
+
async function up(knex) {
|
|
7
|
+
logging.info('Adding on delete SET NULL for comments');
|
|
8
|
+
|
|
9
|
+
await dropForeign({
|
|
10
|
+
fromTable: 'comments',
|
|
11
|
+
fromColumn: 'member_id',
|
|
12
|
+
toTable: 'members',
|
|
13
|
+
toColumn: 'id',
|
|
14
|
+
transaction: knex
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
await addForeign({
|
|
18
|
+
fromTable: 'comments',
|
|
19
|
+
fromColumn: 'member_id',
|
|
20
|
+
toTable: 'members',
|
|
21
|
+
toColumn: 'id',
|
|
22
|
+
setNullDelete: true,
|
|
23
|
+
transaction: knex
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
logging.info('Adding on delete CASCADE for comment_likes');
|
|
27
|
+
|
|
28
|
+
await dropForeign({
|
|
29
|
+
fromTable: 'comment_likes',
|
|
30
|
+
fromColumn: 'member_id',
|
|
31
|
+
toTable: 'members',
|
|
32
|
+
toColumn: 'id',
|
|
33
|
+
transaction: knex
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
await addForeign({
|
|
37
|
+
fromTable: 'comment_likes',
|
|
38
|
+
fromColumn: 'member_id',
|
|
39
|
+
toTable: 'members',
|
|
40
|
+
toColumn: 'id',
|
|
41
|
+
cascadeDelete: true,
|
|
42
|
+
transaction: knex
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
logging.info('Adding on delete SET NULL for comment_reports');
|
|
46
|
+
|
|
47
|
+
await dropForeign({
|
|
48
|
+
fromTable: 'comment_reports',
|
|
49
|
+
fromColumn: 'member_id',
|
|
50
|
+
toTable: 'members',
|
|
51
|
+
toColumn: 'id',
|
|
52
|
+
transaction: knex
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await addForeign({
|
|
56
|
+
fromTable: 'comment_reports',
|
|
57
|
+
fromColumn: 'member_id',
|
|
58
|
+
toTable: 'members',
|
|
59
|
+
toColumn: 'id',
|
|
60
|
+
setNullDelete: true,
|
|
61
|
+
transaction: knex
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
async function down(knex) {
|
|
65
|
+
logging.info('Restoring foreign key for comments');
|
|
66
|
+
|
|
67
|
+
await dropForeign({
|
|
68
|
+
fromTable: 'comments',
|
|
69
|
+
fromColumn: 'member_id',
|
|
70
|
+
toTable: 'members',
|
|
71
|
+
toColumn: 'id',
|
|
72
|
+
transaction: knex
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await addForeign({
|
|
76
|
+
fromTable: 'comments',
|
|
77
|
+
fromColumn: 'member_id',
|
|
78
|
+
toTable: 'members',
|
|
79
|
+
toColumn: 'id',
|
|
80
|
+
transaction: knex
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
logging.info('Restoring foreign key for comment_likes');
|
|
84
|
+
|
|
85
|
+
await dropForeign({
|
|
86
|
+
fromTable: 'comment_likes',
|
|
87
|
+
fromColumn: 'member_id',
|
|
88
|
+
toTable: 'members',
|
|
89
|
+
toColumn: 'id',
|
|
90
|
+
transaction: knex
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await addForeign({
|
|
94
|
+
fromTable: 'comment_likes',
|
|
95
|
+
fromColumn: 'member_id',
|
|
96
|
+
toTable: 'members',
|
|
97
|
+
toColumn: 'id',
|
|
98
|
+
transaction: knex
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
logging.info('Restoring foreign key for comment_reports');
|
|
102
|
+
|
|
103
|
+
await dropForeign({
|
|
104
|
+
fromTable: 'comment_reports',
|
|
105
|
+
fromColumn: 'member_id',
|
|
106
|
+
toTable: 'members',
|
|
107
|
+
toColumn: 'id',
|
|
108
|
+
transaction: knex
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await addForeign({
|
|
112
|
+
fromTable: 'comment_reports',
|
|
113
|
+
fromColumn: 'member_id',
|
|
114
|
+
toTable: 'members',
|
|
115
|
+
toColumn: 'id',
|
|
116
|
+
transaction: knex
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const {addTable} = require('../../utils');
|
|
2
|
+
|
|
3
|
+
module.exports = addTable('jobs', {
|
|
4
|
+
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
5
|
+
name: {type: 'string', maxlength: 191, nullable: false, unique: true},
|
|
6
|
+
status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'queued', validations: {isIn: [['started', 'finished', 'failed', 'queued']]}},
|
|
7
|
+
started_at: {type: 'dateTime', nullable: true},
|
|
8
|
+
finished_at: {type: 'dateTime', nullable: true},
|
|
9
|
+
created_at: {type: 'dateTime', nullable: false},
|
|
10
|
+
updated_at: {type: 'dateTime', nullable: true}
|
|
11
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
3
|
+
|
|
4
|
+
module.exports = createTransactionalMigration(
|
|
5
|
+
async function up(knex) {
|
|
6
|
+
logging.info('Changing Ghost Explore Integration to type "builtin"');
|
|
7
|
+
await knex('integrations')
|
|
8
|
+
.where({
|
|
9
|
+
name: 'Ghost Explore',
|
|
10
|
+
slug: 'ghost-explore'
|
|
11
|
+
})
|
|
12
|
+
.update('type', 'builtin');
|
|
13
|
+
},
|
|
14
|
+
async function down(knex) {
|
|
15
|
+
logging.info('Changing Ghost Explore Integration to type "internal"');
|
|
16
|
+
|
|
17
|
+
await knex('integrations')
|
|
18
|
+
.where({
|
|
19
|
+
name: 'Ghost Explore',
|
|
20
|
+
slug: 'ghost-explore'
|
|
21
|
+
})
|
|
22
|
+
.update('type', 'internal');
|
|
23
|
+
}
|
|
24
|
+
);
|
|
@@ -50,6 +50,8 @@ function addTableColumn(tableName, table, columnName, columnSpec = schema[tableN
|
|
|
50
50
|
}
|
|
51
51
|
if (Object.prototype.hasOwnProperty.call(columnSpec, 'cascadeDelete') && columnSpec.cascadeDelete === true) {
|
|
52
52
|
column.onDelete('CASCADE');
|
|
53
|
+
} else if (Object.prototype.hasOwnProperty.call(columnSpec, 'setNullDelete') && columnSpec.setNullDelete === true) {
|
|
54
|
+
column.onDelete('SET NULL');
|
|
53
55
|
}
|
|
54
56
|
if (Object.prototype.hasOwnProperty.call(columnSpec, 'defaultTo')) {
|
|
55
57
|
column.defaultTo(columnSpec.defaultTo);
|
|
@@ -206,10 +208,11 @@ async function hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, trans
|
|
|
206
208
|
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
|
|
207
209
|
* @param {string} configuration.toTable - name of the table to point the foreign key to
|
|
208
210
|
* @param {string} configuration.toColumn - column of the table to point the foreign key to
|
|
209
|
-
* @param {Boolean} configuration.cascadeDelete - adds the "on delete cascade" option if true
|
|
211
|
+
* @param {Boolean} [configuration.cascadeDelete] - adds the "on delete cascade" option if true
|
|
212
|
+
* @param {Boolean} [configuration.setNullDelete] - adds the "on delete SET NULL" option if true
|
|
210
213
|
* @param {import('knex')} configuration.transaction - connection object containing knex reference
|
|
211
214
|
*/
|
|
212
|
-
async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDelete = false, transaction = db.knex}) {
|
|
215
|
+
async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDelete = false, setNullDelete = false, transaction = db.knex}) {
|
|
213
216
|
if (DatabaseInfo.isSQLite(transaction)) {
|
|
214
217
|
const foreignKeyExists = await hasForeignSQLite({fromTable, fromColumn, toTable, toColumn, transaction});
|
|
215
218
|
if (foreignKeyExists) {
|
|
@@ -232,6 +235,8 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, cascadeDele
|
|
|
232
235
|
await transaction.schema.table(fromTable, function (table) {
|
|
233
236
|
if (cascadeDelete) {
|
|
234
237
|
table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('CASCADE');
|
|
238
|
+
} else if (setNullDelete) {
|
|
239
|
+
table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('SET NULL');
|
|
235
240
|
} else {
|
|
236
241
|
table.foreign(fromColumn).references(`${toTable}.${toColumn}`);
|
|
237
242
|
}
|
|
@@ -610,6 +610,11 @@
|
|
|
610
610
|
"name": "Unlike comments",
|
|
611
611
|
"action_type": "unlike",
|
|
612
612
|
"object_type": "comment"
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"name": "Report comments",
|
|
616
|
+
"action_type": "report",
|
|
617
|
+
"object_type": "comment"
|
|
613
618
|
}
|
|
614
619
|
]
|
|
615
620
|
},
|
|
@@ -667,7 +672,7 @@
|
|
|
667
672
|
"slug": "ghost-explore",
|
|
668
673
|
"name": "Ghost Explore",
|
|
669
674
|
"description": "Built-in Ghost Explore integration",
|
|
670
|
-
"type": "
|
|
675
|
+
"type": "builtin",
|
|
671
676
|
"api_keys": [{"type": "admin", "role": "Ghost Explore Integration"}]
|
|
672
677
|
},
|
|
673
678
|
{
|
|
@@ -750,7 +750,7 @@ module.exports = {
|
|
|
750
750
|
comments: {
|
|
751
751
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
752
752
|
post_id: {type: 'string', maxlength: 24, nullable: false, unique: false, references: 'posts.id', cascadeDelete: true},
|
|
753
|
-
member_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'members.id'},
|
|
753
|
+
member_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'members.id', setNullDelete: true},
|
|
754
754
|
parent_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'comments.id'},
|
|
755
755
|
status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'published', validations: {isIn: [['published', 'hidden', 'deleted']]}},
|
|
756
756
|
html: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true},
|
|
@@ -761,16 +761,24 @@ module.exports = {
|
|
|
761
761
|
comment_likes: {
|
|
762
762
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
763
763
|
comment_id: {type: 'string', maxlength: 24, nullable: false, unique: false, references: 'comments.id', cascadeDelete: true},
|
|
764
|
-
member_id: {type: 'string', maxlength: 24, nullable:
|
|
764
|
+
member_id: {type: 'string', maxlength: 24, nullable: false, unique: false, references: 'members.id', cascadeDelete: true},
|
|
765
765
|
created_at: {type: 'dateTime', nullable: false},
|
|
766
766
|
updated_at: {type: 'dateTime', nullable: false}
|
|
767
767
|
},
|
|
768
768
|
comment_reports: {
|
|
769
769
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
770
770
|
comment_id: {type: 'string', maxlength: 24, nullable: false, unique: false, references: 'comments.id', cascadeDelete: true},
|
|
771
|
-
member_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'members.id'},
|
|
772
|
-
reason: {type: 'text', maxlength: 65535, nullable: false},
|
|
771
|
+
member_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'members.id', setNullDelete: true},
|
|
773
772
|
created_at: {type: 'dateTime', nullable: false},
|
|
774
773
|
updated_at: {type: 'dateTime', nullable: false}
|
|
774
|
+
},
|
|
775
|
+
jobs: {
|
|
776
|
+
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
777
|
+
name: {type: 'string', maxlength: 191, nullable: false, unique: true},
|
|
778
|
+
status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'queued', validations: {isIn: [['started', 'finished', 'failed', 'queued']]}},
|
|
779
|
+
started_at: {type: 'dateTime', nullable: true},
|
|
780
|
+
finished_at: {type: 'dateTime', nullable: true},
|
|
781
|
+
created_at: {type: 'dateTime', nullable: false},
|
|
782
|
+
updated_at: {type: 'dateTime', nullable: true}
|
|
775
783
|
}
|
|
776
784
|
};
|
|
@@ -213,9 +213,6 @@ class GhostServer {
|
|
|
213
213
|
* Internal Method for TestMode.
|
|
214
214
|
*/
|
|
215
215
|
_startTestMode() {
|
|
216
|
-
// This is horrible and very temporary
|
|
217
|
-
const jobService = require('./services/jobs');
|
|
218
|
-
|
|
219
216
|
// Output how many connections are open every 5 seconds
|
|
220
217
|
const connectionInterval = setInterval(() => this.httpServer.getConnections(
|
|
221
218
|
(err, connections) => logging.warn(`${connections} connections currently open`)
|
|
@@ -226,25 +223,6 @@ class GhostServer {
|
|
|
226
223
|
clearInterval(connectionInterval);
|
|
227
224
|
logging.warn('Server has fully closed');
|
|
228
225
|
});
|
|
229
|
-
|
|
230
|
-
// Output job queue length every 5 seconds
|
|
231
|
-
setInterval(() => {
|
|
232
|
-
logging.warn(`${jobService.queue.length()} jobs in the queue. Idle: ${jobService.queue.idle()}`);
|
|
233
|
-
|
|
234
|
-
const runningScheduledjobs = Object.keys(jobService.bree.workers);
|
|
235
|
-
if (Object.keys(jobService.bree.workers).length) {
|
|
236
|
-
logging.warn(`${Object.keys(jobService.bree.workers).length} jobs running: ${runningScheduledjobs}`);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const scheduledJobs = Object.keys(jobService.bree.intervals);
|
|
240
|
-
if (Object.keys(jobService.bree.intervals).length) {
|
|
241
|
-
logging.warn(`${Object.keys(jobService.bree.intervals).length} scheduled jobs: ${scheduledJobs}`);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (runningScheduledjobs.length === 0 && scheduledJobs.length === 0) {
|
|
245
|
-
logging.warn('No scheduled or running jobs');
|
|
246
|
-
}
|
|
247
|
-
}, 5000);
|
|
248
226
|
}
|
|
249
227
|
|
|
250
228
|
/**
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const ghostBookshelf = require('./base');
|
|
2
|
+
|
|
3
|
+
const CommentReport = ghostBookshelf.Model.extend({
|
|
4
|
+
tableName: 'comment_reports',
|
|
5
|
+
|
|
6
|
+
defaults: function defaults() {
|
|
7
|
+
return {};
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
comment() {
|
|
11
|
+
return this.belongsTo('Comment', 'comment_id');
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
member() {
|
|
15
|
+
return this.belongsTo('Member', 'member_id');
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
emitChange: function emitChange(event, options) {
|
|
19
|
+
const eventToTrigger = 'comment_report' + '.' + event;
|
|
20
|
+
ghostBookshelf.Model.prototype.emitChange.bind(this)(this, eventToTrigger, options);
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
onCreated: function onCreated(model, options) {
|
|
24
|
+
ghostBookshelf.Model.prototype.onCreated.apply(this, arguments);
|
|
25
|
+
|
|
26
|
+
model.emitChange('added', options);
|
|
27
|
+
}
|
|
28
|
+
}, {
|
|
29
|
+
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
CommentReport: ghostBookshelf.model('CommentReport', CommentReport)
|
|
34
|
+
};
|
|
@@ -2,7 +2,6 @@ const ghostBookshelf = require('./base');
|
|
|
2
2
|
const _ = require('lodash');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
4
|
const tpl = require('@tryghost/tpl');
|
|
5
|
-
const commentsService = require('../services/comments');
|
|
6
5
|
|
|
7
6
|
const messages = {
|
|
8
7
|
commentNotFound: 'Comment could not be found',
|
|
@@ -70,14 +69,14 @@ const Comment = ghostBookshelf.Model.extend({
|
|
|
70
69
|
onCreated: function onCreated(model, options) {
|
|
71
70
|
ghostBookshelf.Model.prototype.onCreated.apply(this, arguments);
|
|
72
71
|
|
|
73
|
-
if (!options.context.internal) {
|
|
74
|
-
commentsService.api.sendNewCommentNotifications(model);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
72
|
model.emitChange('added', options);
|
|
78
73
|
},
|
|
79
74
|
|
|
80
|
-
enforcedFilters: function enforcedFilters() {
|
|
75
|
+
enforcedFilters: function enforcedFilters(options) {
|
|
76
|
+
if (options.context && options.context.user) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
81
80
|
return 'parent_id:null';
|
|
82
81
|
}
|
|
83
82
|
|
|
@@ -151,7 +150,9 @@ const Comment = ghostBookshelf.Model.extend({
|
|
|
151
150
|
defaultRelations: function defaultRelations(methodName, options) {
|
|
152
151
|
// @todo: the default relations are not working for 'add' when we add it below
|
|
153
152
|
if (['findAll', 'findPage', 'edit', 'findOne'].indexOf(methodName) !== -1) {
|
|
154
|
-
options.withRelated
|
|
153
|
+
if (!options.withRelated || options.withRelated.length === 0) {
|
|
154
|
+
options.withRelated = ['member', 'likes', 'replies', 'replies.member', 'replies.likes'];
|
|
155
|
+
}
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
return options;
|
|
@@ -7,6 +7,7 @@ const logging = require('@tryghost/logging');
|
|
|
7
7
|
const models = require('../../models');
|
|
8
8
|
const mailgunProvider = require('./mailgun');
|
|
9
9
|
const sentry = require('../../../shared/sentry');
|
|
10
|
+
const labs = require('../../../shared/labs');
|
|
10
11
|
const debug = require('@tryghost/debug')('mega');
|
|
11
12
|
const postEmailSerializer = require('../mega/post-email-serializer');
|
|
12
13
|
|
|
@@ -170,6 +171,11 @@ module.exports = {
|
|
|
170
171
|
// Load newsletter data on email
|
|
171
172
|
await emailBatchModel.relations.email.getLazyRelation('newsletter', {require: false, ...knexOptions});
|
|
172
173
|
|
|
174
|
+
if (labs.isSet('newsletterPaywall')) {
|
|
175
|
+
// Load post data on email - for content gating on paywall
|
|
176
|
+
await emailBatchModel.relations.email.getLazyRelation('post', {require: false, ...knexOptions});
|
|
177
|
+
}
|
|
178
|
+
|
|
173
179
|
// send the email
|
|
174
180
|
const sendResponse = await this.send(emailBatchModel.relations.email.toJSON(), recipientRows, memberSegment);
|
|
175
181
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('../../api/shared/frame')} Frame
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const {MethodNotAllowedError} = require('@tryghost/errors');
|
|
6
|
+
const tpl = require('@tryghost/tpl');
|
|
7
|
+
|
|
8
|
+
const messages = {
|
|
9
|
+
cannotDestroyComments: 'You cannot destroy comments.'
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = class CommentsController {
|
|
13
|
+
/**
|
|
14
|
+
* @param {import('./service')} service
|
|
15
|
+
*/
|
|
16
|
+
constructor(service) {
|
|
17
|
+
this.service = service;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {Frame} frame
|
|
22
|
+
*/
|
|
23
|
+
async browse(frame) {
|
|
24
|
+
return this.service.getComments(frame.options);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Frame} frame
|
|
29
|
+
*/
|
|
30
|
+
async read(frame) {
|
|
31
|
+
return await this.service.getCommentByID(frame.data.id, frame.options);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {Frame} frame
|
|
36
|
+
*/
|
|
37
|
+
async edit(frame) {
|
|
38
|
+
if (frame.data.comments[0].status === 'deleted') {
|
|
39
|
+
return await this.service.deleteComment(
|
|
40
|
+
frame.options.id,
|
|
41
|
+
frame?.options?.context?.member?.id,
|
|
42
|
+
frame.options
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return await this.service.editCommentContent(
|
|
47
|
+
frame.options.id,
|
|
48
|
+
frame?.options?.context?.member?.id,
|
|
49
|
+
frame.data.comments[0].html,
|
|
50
|
+
frame.options
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {Frame} frame
|
|
56
|
+
*/
|
|
57
|
+
async add(frame) {
|
|
58
|
+
const data = frame.data.comments[0];
|
|
59
|
+
|
|
60
|
+
if (data.parent_id) {
|
|
61
|
+
return await this.service.replyToComment(
|
|
62
|
+
data.parent_id,
|
|
63
|
+
frame.options.context.member.id,
|
|
64
|
+
data.html,
|
|
65
|
+
frame.options
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return await this.service.commentOnPost(
|
|
70
|
+
data.post_id,
|
|
71
|
+
frame.options.context.member.id,
|
|
72
|
+
data.html,
|
|
73
|
+
frame.options
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async destroy() {
|
|
78
|
+
throw new MethodNotAllowedError({
|
|
79
|
+
message: tpl(messages.cannotDestroyComments)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
<tr>
|
|
117
117
|
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
|
|
118
118
|
<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: 20px; color: #15212A; font-weight: bold; line-height: 25px; margin: 0; margin-bottom: 15px;">Hey there,</p>
|
|
119
|
-
<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: 32px;">Someone just replied to your comment on <a href="
|
|
119
|
+
<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: 32px;">Someone just replied to your comment on <a href="{{postUrl}}" target="_blank">{{postTitle}}</a>.</p>
|
|
120
120
|
|
|
121
121
|
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
|
|
122
122
|
<tbody>
|
|
@@ -196,4 +196,4 @@
|
|
|
196
196
|
</tr>
|
|
197
197
|
</table>
|
|
198
198
|
</body>
|
|
199
|
-
</html>
|
|
199
|
+
</html>
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
module.exports = function (data) {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
// Be careful when you indent the email, because whitespaces are visible in emails!
|
|
3
|
+
return `Hey there,
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Someone just replied to your comment on "${data.postTitle}"
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
${data.postUrl}#ghost-comments-root
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
---
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`;
|
|
11
|
+
Sent to ${data.toEmail} from ${data.siteDomain}.
|
|
12
|
+
You can manage your notification preferences at ${data.profileUrl}.`;
|
|
14
13
|
};
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
<tr>
|
|
117
117
|
<td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
|
|
118
118
|
<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: 20px; color: #15212A; font-weight: bold; line-height: 25px; margin: 0; margin-bottom: 15px;">Hey there,</p>
|
|
119
|
-
<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: 32px;">Someone just left a comment on your post <a href="
|
|
119
|
+
<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: 32px;">Someone just left a comment on your post <a href="{{postUrl}}" target="_blank">{{postTitle}}</a>.</p>
|
|
120
120
|
|
|
121
121
|
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; background: #F9F9FA; border-radius: 7px;">
|
|
122
122
|
<tbody>
|
|
@@ -196,4 +196,4 @@
|
|
|
196
196
|
</tr>
|
|
197
197
|
</table>
|
|
198
198
|
</body>
|
|
199
|
-
</html>
|
|
199
|
+
</html>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
module.exports = function (data) {
|
|
2
|
+
// Be careful when you indent the email, because whitespaces are visible in emails!
|
|
2
3
|
return `
|
|
3
|
-
|
|
4
|
+
Hey there,
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
Someone just posted a comment on your post "${data.postTitle}"
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
${data.postUrl}#ghost-comments-root
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
---
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
Sent to ${data.toEmail} from ${data.siteDomain}.
|
|
13
|
+
You can manage your notification preferences at ${data.staffUrl}.
|
|
13
14
|
`;
|
|
14
15
|
};
|