diff --git a/ghost/admin/app/controllers/settings/staff/user.js b/ghost/admin/app/controllers/settings/staff/user.js index 519bfa3b15..3db3c9c615 100644 --- a/ghost/admin/app/controllers/settings/staff/user.js +++ b/ghost/admin/app/controllers/settings/staff/user.js @@ -211,6 +211,11 @@ export default class UserController extends Controller { this.user.commentNotifications = event.target.checked; } + @action + toggleMentionNotifications(event) { + this.user.mentionNotifications = event.target.checked; + } + @action toggleMemberEmailAlerts(type, event) { if (type === 'free-signup') { diff --git a/ghost/admin/app/models/user.js b/ghost/admin/app/models/user.js index 245c6969fe..0d222c158d 100644 --- a/ghost/admin/app/models/user.js +++ b/ghost/admin/app/models/user.js @@ -40,7 +40,7 @@ export default BaseModel.extend(ValidationEngine, { freeMemberSignupNotification: attr(), paidSubscriptionStartedNotification: attr(), paidSubscriptionCanceledNotification: attr(), - + mentionNotifications: attr(), ghostPaths: service(), ajax: service(), session: service(), diff --git a/ghost/admin/app/services/feature.js b/ghost/admin/app/services/feature.js index 2f5a605a83..a971b81edf 100644 --- a/ghost/admin/app/services/feature.js +++ b/ghost/admin/app/services/feature.js @@ -69,7 +69,6 @@ export default class FeatureService extends Service { @feature('emailStability') emailStability; @feature('webmentions') webmentions; @feature('outboundLinkTagging') outboundLinkTagging; - @feature('webmentionEmail') webmentionEmail; @feature('emailErrors') emailErrors; @feature('milestoneEmails') milestoneEmails; diff --git a/ghost/admin/app/templates/settings/labs.hbs b/ghost/admin/app/templates/settings/labs.hbs index 84207be12d..eccd7264bf 100644 --- a/ghost/admin/app/templates/settings/labs.hbs +++ b/ghost/admin/app/templates/settings/labs.hbs @@ -213,19 +213,6 @@ -
-
-
-

Webmention Email Notifications

-

- Receive email notifications when a webmention is received. -

-
-
- -
-
-
diff --git a/ghost/admin/app/templates/settings/staff/user.hbs b/ghost/admin/app/templates/settings/staff/user.hbs index c79cddf435..585b6a4ee9 100644 --- a/ghost/admin/app/templates/settings/staff/user.hbs +++ b/ghost/admin/app/templates/settings/staff/user.hbs @@ -327,6 +327,27 @@ {{/if}} {{/if}} {{/if}} + {{#if (feature 'webmentions')}} +
+
+ +

When you receive a new webmention

+
+
+ +
+
+ {{/if}}
{{/if}} diff --git a/ghost/admin/mirage/factories/user.js b/ghost/admin/mirage/factories/user.js index d99fe93f2c..76c49c0b4e 100644 --- a/ghost/admin/mirage/factories/user.js +++ b/ghost/admin/mirage/factories/user.js @@ -19,7 +19,6 @@ export default Factory.extend({ updatedAt: '2015-11-02T16:12:05.000Z', updatedBy: '1', website: 'http://example.com', - posts() { return []; }, roles() { return []; } }); diff --git a/ghost/admin/tests/acceptance/staff-test.js b/ghost/admin/tests/acceptance/staff-test.js index 9a02eeb400..a618c5004f 100644 --- a/ghost/admin/tests/acceptance/staff-test.js +++ b/ghost/admin/tests/acceptance/staff-test.js @@ -14,6 +14,7 @@ import { focus, triggerEvent } from '@ember/test-helpers'; +import {enableLabsFlag} from '../helpers/labs-flag'; import {enableMembers} from '../helpers/members'; import {enableStripe} from '../helpers/stripe'; import {expect} from 'chai'; @@ -79,6 +80,7 @@ describe('Acceptance: Staff', function () { adminRole = this.server.schema.roles.find(1); enableMembers(this.server); enableStripe(this.server); + enableLabsFlag(this.server, 'webmentions'); admin = this.server.create('user', {email: 'admin@example.com', roles: [adminRole]}); @@ -869,17 +871,20 @@ describe('Acceptance: Staff', function () { expect(find('[data-test-checkbox="free-signup-notifications"]')).to.not.be.checked; expect(find('[data-test-checkbox="paid-started-notifications"]')).to.not.be.checked; expect(find('[data-test-checkbox="paid-canceled-notifications"]')).to.not.be.checked; + expect(find('[data-test-checkbox="mention-notifications"]')).to.not.be.checked; await click('[data-test-label="free-signup-notifications"]'); await click('[data-test-label="paid-started-notifications"]'); await click('[data-test-label="paid-canceled-notifications"]'); - + await click('[data-test-label="mention-notifications"]'); await click('[data-test-save-button]'); - await visit(`/settings/staff/${admin.slug}`); + await visit(`/settings/staff/${admin.slug}`); + expect(find('[data-test-checkbox="free-signup-notifications"]')).to.be.checked; expect(find('[data-test-checkbox="paid-started-notifications"]')).to.be.checked; expect(find('[data-test-checkbox="paid-canceled-notifications"]')).to.be.checked; + expect(find('[data-test-checkbox="mention-notifications"]')).to.be.checked; }); }); diff --git a/ghost/core/core/server/models/user.js b/ghost/core/core/server/models/user.js index 1f3230ea88..da3c767ad1 100644 --- a/ghost/core/core/server/models/user.js +++ b/ghost/core/core/server/models/user.js @@ -505,6 +505,8 @@ User = ghostBookshelf.Model.extend({ filter += '+paid_subscription_started_notification:true'; } else if (type === 'paid-canceled') { filter += '+paid_subscription_canceled_notification:true'; + } else if (type === 'mention-received') { + filter += '+mention_notifications:true'; } const updatedOptions = _.merge({}, options, {filter, withRelated: ['roles']}); return this.findAll(updatedOptions).then((users) => { diff --git a/ghost/core/core/shared/labs.js b/ghost/core/core/shared/labs.js index cb09d52e72..80cf42153c 100644 --- a/ghost/core/core/shared/labs.js +++ b/ghost/core/core/shared/labs.js @@ -35,7 +35,6 @@ const ALPHA_FEATURES = [ 'urlCache', 'beforeAfterCard', 'lexicalEditor', - 'webmentionEmail', 'outboundLinkTagging', 'milestoneEmails' ]; diff --git a/ghost/core/test/e2e-api/webmentions/webmentions.test.js b/ghost/core/test/e2e-api/webmentions/webmentions.test.js index fb5653df6d..3d6f5dbfb9 100644 --- a/ghost/core/test/e2e-api/webmentions/webmentions.test.js +++ b/ghost/core/test/e2e-api/webmentions/webmentions.test.js @@ -19,7 +19,7 @@ describe('Webmentions (receiving)', function () { agent = await agentProvider.getWebmentionsAPIAgent(); await fixtureManager.init('posts'); nock.disableNetConnect(); - mockManager.mockLabsEnabled('webmentionEmail'); + mockManager.mockLabsEnabled('webmentions'); }); after(function () { @@ -136,7 +136,7 @@ describe('Webmentions (receiving)', function () { await processWebmentionJob; await DomainEvents.allSettled(); - const users = await models.User.findAll(); + const users = await models.User.getEmailAlertUsers('mention-received'); users.forEach(async (user) => { await mockManager.assert.sentEmail({ subject: 'You\'ve been mentioned!', @@ -147,7 +147,7 @@ describe('Webmentions (receiving)', function () { }); it('does not send notification with flag disabled', async function () { - mockManager.mockLabsDisabled('webmentionEmail'); + mockManager.mockLabsDisabled('webmentions'); const processWebmentionJob = jobsService.awaitCompletion('processWebmention'); const targetUrl = new URL('integrations/', urlUtils.getSiteUrl()); const sourceUrl = new URL('http://testpage.com/external-article-123-email-test/'); diff --git a/ghost/staff-service/lib/emails.js b/ghost/staff-service/lib/emails.js index eda8bff677..45864d079b 100644 --- a/ghost/staff-service/lib/emails.js +++ b/ghost/staff-service/lib/emails.js @@ -143,9 +143,24 @@ class StaffServiceEmails { } async notifyMentionReceived({mention}) { - const users = await this.models.User.findAll(); // sending to all staff users for now + const users = await this.models.User.getEmailAlertUsers('mention-received'); + let resource = null; + if (mention.resourceId) { + try { + const postModel = await this.models.Post.findOne({id: mention.resourceId.toString()}); + if (postModel) { + resource = { + id: postModel.id, + name: postModel.get('title'), + type: 'post' + }; + } + } catch (err) { + this.logging.error(err); + } + } for (const user of users) { - const to = user.toJSON().email; + const to = user.email; const subject = `💌 New mention from: ${mention.sourceSiteTitle}`; const templateData = { @@ -155,13 +170,14 @@ class StaffServiceEmails { sourceSiteTitle: mention.sourceSiteTitle, sourceFavicon: mention.sourceFavicon, sourceAuthor: mention.sourceAuthor, + resource, siteTitle: this.settingsCache.get('title'), siteUrl: this.urlUtils.getSiteUrl(), siteDomain: this.siteDomain, accentColor: this.settingsCache.get('accent_color'), fromEmail: this.fromEmailAddress, toEmail: to, - staffUrl: this.urlUtils.urlJoin(this.urlUtils.urlFor('admin', true), '#', `/settings/staff/${user.toJSON().slug}`) + staffUrl: this.urlUtils.urlJoin(this.urlUtils.urlFor('admin', true), '#', `/settings/staff/${user.slug}`) }; const {html, text} = await this.renderEmailTemplate('new-mention-received', templateData); diff --git a/ghost/staff-service/lib/staff-service.js b/ghost/staff-service/lib/staff-service.js index b713d29834..0b6fe42b72 100644 --- a/ghost/staff-service/lib/staff-service.js +++ b/ghost/staff-service/lib/staff-service.js @@ -77,7 +77,7 @@ class StaffService { /** @private */ async handleEvent(type, event) { - if (type === MentionCreatedEvent && event.data.mention && this.labs.isSet('webmentionEmail')) { + if (type === MentionCreatedEvent && event.data.mention && this.labs.isSet('webmentions')) { await this.emails.notifyMentionReceived(event.data); } if (!['api', 'member'].includes(event.data.source)) { diff --git a/ghost/staff-service/test/staff-service.test.js b/ghost/staff-service/test/staff-service.test.js index 51c49542b8..f2ab18a81a 100644 --- a/ghost/staff-service/test/staff-service.test.js +++ b/ghost/staff-service/test/staff-service.test.js @@ -269,7 +269,7 @@ describe('StaffService', function () { urlUtils, settingsHelpers, labs: { - isSet: () => 'webmentionEmail' + isSet: () => 'webmentions' } }); });