diff --git a/ghost/admin/app/components/posts/analytics.hbs b/ghost/admin/app/components/posts/analytics.hbs
index 8157a95de0..82040680b8 100644
--- a/ghost/admin/app/components/posts/analytics.hbs
+++ b/ghost/admin/app/components/posts/analytics.hbs
@@ -85,23 +85,23 @@
/>
{{/if}}
- {{/if}}
- {{#if this.post.showAudienceFeedback }}
-
- {{svg-jar "analytics-tab-feedback-large"}}{{format-number this.post.count.positive_feedback}}
- {{svg-jar "analytics-tab-feedback"}}Feedback — {{this.post.sentiment}}%
-
+ {{#if this.post.isFeedbackEnabledForEmail }}
+
+ {{svg-jar "analytics-tab-feedback-large"}}{{format-number this.post.count.positive_feedback}}
+ {{svg-jar "analytics-tab-feedback"}}Feedback — {{this.post.sentiment}}%
+
-
-
-
+
+
+
+ {{/if}}
{{/if}}
{{#if this.post.showAttributionAnalytics }}
diff --git a/ghost/admin/app/models/email.js b/ghost/admin/app/models/email.js
index d4c7c7ccb3..4c51d6c870 100644
--- a/ghost/admin/app/models/email.js
+++ b/ghost/admin/app/models/email.js
@@ -21,6 +21,8 @@ export default Model.extend({
trackOpens: attr('boolean'),
trackClicks: attr('boolean'),
+ feedbackEnabled: attr('boolean'),
+
createdAtUTC: attr('moment-utc'),
createdBy: attr('string'),
updatedAtUTC: attr('moment-utc'),
diff --git a/ghost/admin/app/models/post.js b/ghost/admin/app/models/post.js
index c8b0eacb42..ac63caa992 100644
--- a/ghost/admin/app/models/post.js
+++ b/ghost/admin/app/models/post.js
@@ -251,6 +251,8 @@ export default Model.extend(Comparable, ValidationEngine, {
return this.get('ghostPaths.url').join(blogUrl, previewKeyword, uuid);
}),
+ isFeedbackEnabledForEmail: computed.reads('email.feedbackEnabled'),
+
isPublic: computed('visibility', function () {
return this.visibility === 'public' ? true : false;
}),
diff --git a/ghost/core/core/server/data/migrations/versions/5.21/2022-10-26-09-32-add-feedback-enabled-column-to-emails.js b/ghost/core/core/server/data/migrations/versions/5.21/2022-10-26-09-32-add-feedback-enabled-column-to-emails.js
new file mode 100644
index 0000000000..46bcfda420
--- /dev/null
+++ b/ghost/core/core/server/data/migrations/versions/5.21/2022-10-26-09-32-add-feedback-enabled-column-to-emails.js
@@ -0,0 +1,7 @@
+const {createAddColumnMigration} = require('../../utils');
+
+module.exports = createAddColumnMigration('emails', 'feedback_enabled', {
+ type: 'boolean',
+ nullable: false,
+ defaultTo: false
+});
diff --git a/ghost/core/core/server/data/schema/schema.js b/ghost/core/core/server/data/schema/schema.js
index 567b9228cc..09614af37d 100644
--- a/ghost/core/core/server/data/schema/schema.js
+++ b/ghost/core/core/server/data/schema/schema.js
@@ -783,6 +783,7 @@ module.exports = {
plaintext: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true},
track_opens: {type: 'boolean', nullable: false, defaultTo: false},
track_clicks: {type: 'boolean', nullable: false, defaultTo: false},
+ feedback_enabled: {type: 'boolean', nullable: false, defaultTo: false},
submitted_at: {type: 'dateTime', nullable: false},
newsletter_id: {type: 'string', maxlength: 24, nullable: true, references: 'newsletters.id'},
created_at: {type: 'dateTime', nullable: false},
diff --git a/ghost/core/core/server/models/email.js b/ghost/core/core/server/models/email.js
index a0788b8fe6..2f2632b7a0 100644
--- a/ghost/core/core/server/models/email.js
+++ b/ghost/core/core/server/models/email.js
@@ -11,6 +11,7 @@ const Email = ghostBookshelf.Model.extend({
recipient_filter: 'status:-free',
track_opens: false,
track_clicks: false,
+ feedback_enabled: false,
delivered_count: 0,
opened_count: 0,
failed_count: 0
diff --git a/ghost/core/core/server/services/mega/mega.js b/ghost/core/core/server/services/mega/mega.js
index 641e19b0b7..921d3a82f2 100644
--- a/ghost/core/core/server/services/mega/mega.js
+++ b/ghost/core/core/server/services/mega/mega.js
@@ -240,6 +240,7 @@ const addEmail = async (postModel, options) => {
submitted_at: moment().toDate(),
track_opens: !!settingsCache.get('email_track_opens'),
track_clicks: !!settingsCache.get('email_track_clicks'),
+ feedback_enabled: !!newsletter.get('feedback_enabled'),
recipient_filter: emailRecipientFilter,
newsletter_id: newsletter.id
}, knexOptions);
diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap
index 7d1bf8e8ca..207254b08f 100644
--- a/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap
+++ b/ghost/core/test/e2e-api/admin/__snapshots__/activity-feed.test.js.snap
@@ -81,7 +81,7 @@ exports[`Activity Feed API Can filter events by post id 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "23031",
+ "content-length": "23206",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@@ -401,7 +401,7 @@ exports[`Activity Feed API Returns email delivered events in activity feed 2: [h
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "1246",
+ "content-length": "1271",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@@ -434,7 +434,7 @@ exports[`Activity Feed API Returns email opened events in activity feed 2: [head
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "1243",
+ "content-length": "1268",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@@ -483,7 +483,7 @@ exports[`Activity Feed API Returns email sent events in activity feed 2: [header
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "5774",
+ "content-length": "5899",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/emails.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/emails.test.js.snap
index 74466f3e17..c37abf11d5 100644
--- a/ghost/core/test/e2e-api/admin/__snapshots__/emails.test.js.snap
+++ b/ghost/core/test/e2e-api/admin/__snapshots__/emails.test.js.snap
@@ -10,6 +10,7 @@ Object {
"error": null,
"error_data": null,
"failed_count": 0,
+ "feedback_enabled": false,
"from": null,
"html": "
Look! I'm an email
",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
@@ -34,6 +35,7 @@ Object {
"error": "Everything went south",
"error_data": null,
"failed_count": 0,
+ "feedback_enabled": false,
"from": null,
"html": "What's that? Another email!
",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
@@ -69,7 +71,7 @@ exports[`Emails API Can browse emails 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "1285",
+ "content-length": "1335",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@@ -87,6 +89,7 @@ Object {
"error": null,
"error_data": null,
"failed_count": 0,
+ "feedback_enabled": false,
"from": null,
"html": "Look! I'm an email
",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
@@ -112,7 +115,7 @@ exports[`Emails API Can read an email 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "582",
+ "content-length": "607",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@@ -130,6 +133,7 @@ Object {
"error": "Everything went south",
"error_data": null,
"failed_count": 0,
+ "feedback_enabled": false,
"from": null,
"html": "What's that? Another email!
",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
@@ -155,7 +159,7 @@ exports[`Emails API Can retry a failed email 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
- "content-length": "628",
+ "content-length": "653",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
diff --git a/ghost/core/test/unit/server/data/schema/integrity.test.js b/ghost/core/test/unit/server/data/schema/integrity.test.js
index a438be33ee..4f08100757 100644
--- a/ghost/core/test/unit/server/data/schema/integrity.test.js
+++ b/ghost/core/test/unit/server/data/schema/integrity.test.js
@@ -35,7 +35,7 @@ const validateRouteSettings = require('../../../../../core/server/services/route
*/
describe('DB version integrity', function () {
// Only these variables should need updating
- const currentSchemaHash = 'bb9d35d276f407c4a353e22e1e5b5538';
+ const currentSchemaHash = 'f94be1265fce0bfbe5c98cb02610f9de';
const currentFixturesHash = 'dcb7ba7c66b4b98d6c26a722985e756a';
const currentSettingsHash = '2978a5684a2d5fcf089f61f5d368a0c0';
const currentRoutesHash = '3d180d52c663d173a6be791ef411ed01';