From 9d6bcdba471288c9f6a930cb78ff53c04198b06f Mon Sep 17 00:00:00 2001 From: Elena Baidakova Date: Fri, 18 Nov 2022 14:33:48 +0400 Subject: [PATCH] Added spam event to feed in frontend admin (#15847) closes TryGhost/Team#2248 --- .../app/components/member/activity-feed.hbs | 2 +- .../members-activity/event-type-filter.js | 12 ++- .../app/helpers/members-event-fetcher.js | 73 +++++++++++++++++++ .../admin/app/helpers/members-event-filter.js | 2 +- ghost/admin/app/helpers/parse-member-event.js | 10 ++- .../admin/app/templates/members-activity.hbs | 4 +- ...ail-delivery-spam--feature-attribution.svg | 5 ++ .../icons/event-email-delivery-spam.svg | 5 ++ 8 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 ghost/admin/public/assets/icons/event-email-delivery-spam--feature-attribution.svg create mode 100644 ghost/admin/public/assets/icons/event-email-delivery-spam.svg diff --git a/ghost/admin/app/components/member/activity-feed.hbs b/ghost/admin/app/components/member/activity-feed.hbs index 4786014d78..ac8f97f055 100644 --- a/ghost/admin/app/components/member/activity-feed.hbs +++ b/ghost/admin/app/components/member/activity-feed.hbs @@ -6,7 +6,7 @@ {{else}} - {{#let (members-event-fetcher filter=(members-event-filter member=@member.id excludedEvents=this.excludedEventTypes) pageSize=5) as |eventsFetcher|}} + {{#let (members-event-fetcher filter=(members-event-filter member=@member.id excludedEvents=this.excludedEventTypes) pageSize=5 memberId=@member.id) as |eventsFetcher|}}
diff --git a/ghost/admin/app/components/members-activity/event-type-filter.js b/ghost/admin/app/components/members-activity/event-type-filter.js index 920e53dc8e..896145ac21 100644 --- a/ghost/admin/app/components/members-activity/event-type-filter.js +++ b/ghost/admin/app/components/members-activity/event-type-filter.js @@ -2,7 +2,8 @@ import Component from '@glimmer/component'; import {action} from '@ember/object'; import {inject as service} from '@ember/service'; -const ALL_EVENT_TYPES = [ +// todo: replace function with const after suppressionList feature flag will be removed +const ALL_EVENT_TYPES = feature => ([ {event: 'signup_event', icon: 'event-filter-signup', name: 'Signups'}, {event: 'login_event', icon: 'event-filter-login', name: 'Logins'}, {event: 'subscription_event', icon: 'event-filter-subscription', name: 'Paid subscriptions'}, @@ -10,15 +11,18 @@ const ALL_EVENT_TYPES = [ {event: 'newsletter_event', icon: 'event-filter-newsletter', name: 'Email subscriptions'}, {event: 'email_opened_event', icon: 'event-filter-email-opened', name: 'Email opens'}, {event: 'email_delivered_event', icon: 'event-filter-email-delivered', name: 'Email deliveries'}, - {event: 'email_failed_event', icon: 'event-filter-email-failed', name: 'Email failures'} -]; + {event: 'email_failed_event', icon: 'event-filter-email-failed', name: feature.suppressionList ? 'Email bounces' : 'Email failures'} +]); export default class MembersActivityEventTypeFilter extends Component { @service settings; @service feature; get availableEventTypes() { - const extended = [...ALL_EVENT_TYPES]; + const extended = [...ALL_EVENT_TYPES(this.feature)]; + if (this.feature.suppressionList) { + extended.push({event: 'email_complaint_event', icon: 'event-filter-email-spam', name: 'Email spam'}); + } if (this.settings.commentsEnabled !== 'off') { extended.push({event: 'comment_event', icon: 'event-comment', name: 'Comments'}); } diff --git a/ghost/admin/app/helpers/members-event-fetcher.js b/ghost/admin/app/helpers/members-event-fetcher.js index 36933464b2..1350626a69 100644 --- a/ghost/admin/app/helpers/members-event-fetcher.js +++ b/ghost/admin/app/helpers/members-event-fetcher.js @@ -10,6 +10,7 @@ export default class MembersEventsFetcher extends Resource { @service ajax; @service ghostPaths; @service store; + @service feature; @tracked data = new TrackedArray([]); @tracked isLoading = false; @@ -106,6 +107,23 @@ export default class MembersEventsFetcher extends Resource { } this.data.push(...events); + + // todo: remove all condition block when backend will be ready + if (this.feature.suppressionList && !queryParams.filter.includes('email_delivered_event')) { + const memberId = this.args.named.memberId; + if (!this.args.named.memberId) { + return; + } + const member = yield this.store.findRecord('member', memberId); + if (member.email === 'spam@ghost.org') { + this.data.unshift(mockData('email_delivered_event')); + this.data.unshift(mockData('email_complaint_event')); + } + + if (member.email === 'fail@ghost.org') { + this.data.unshift(mockData('email_failed_event')); + } + } } catch (e) { this.isError = true; @@ -121,3 +139,58 @@ export default class MembersEventsFetcher extends Resource { } } } + +function mockData(eventType) { + return ({ + type: eventType, + data: { + id: '6375cc411ebedb499bef54c7', + member_id: '63737a1719675aed3b7cc988', + created_at: moment.utc(), + member: { + id: '63737a1719675aed3b7cc988', + uuid: '5c753e47-9f49-43ad-86d4-c5c0168519a2', + email: 'spam@ghost.org', + status: 'free', + name: 'Spam', + expertise: null, + note: null, + geolocation: null, + enable_comment_notifications: true, + email_count: 6, + email_opened_count: 2, + email_open_rate: 33, + last_seen_at: '2022-11-16T04:44:19.000Z', + last_commented_at: null, + created_at: '2022-11-15T11:37:59.000Z', + updated_at: '2022-11-17T05:33:13.000Z', + avatar_image: 'https://www.gravatar.com/avatar/0e0d23869265932bca724acda6c7e529?s=250&r=g&d=blank' + }, + email: { + id: '6375cc411ebedb499bef54c4', + post_id: '6375cc3e1ebedb499bef54b5', + uuid: '01f393bd-b487-4540-995f-d09ad47059d8', + status: 'submitted', + recipient_filter: 'all', + error: null, + error_data: '[]', + email_count: 2, + delivered_count: 2, + opened_count: 0, + failed_count: 0, + subject: 'Spam test', + from: '"local"', + reply_to: 'noreply@localhost', + html: '\n\n\n\n\n\n\nSpam test\n\n\n\n\n \n \n\n \n \n\n \n \n \n \n \n\n \n\n \n\n\n', + plaintext: null, + track_opens: true, + track_clicks: true, + submitted_at: '2022-11-17T05:53:05.000Z', + newsletter_id: '123', + created_at: '2022-11-17T05:53:05.000Z', + updated_at: '2022-11-17T05:53:07.000Z', + feedback_enabled: true + } + } + }); +} diff --git a/ghost/admin/app/helpers/members-event-filter.js b/ghost/admin/app/helpers/members-event-filter.js index a87d0a4b3a..cd66d0c514 100644 --- a/ghost/admin/app/helpers/members-event-filter.js +++ b/ghost/admin/app/helpers/members-event-filter.js @@ -3,7 +3,7 @@ import classic from 'ember-classic-decorator'; import {isBlank} from '@ember/utils'; import {inject as service} from '@ember/service'; -export const EMAIL_EVENTS = ['email_sent_event', 'email_delivered_event', 'email_opened_event','email_failed_event']; +export const EMAIL_EVENTS = ['email_sent_event', 'email_delivered_event', 'email_opened_event','email_failed_event', 'email_complaint_event']; export const NEWSLETTER_EVENTS = ['newsletter_event']; @classic diff --git a/ghost/admin/app/helpers/parse-member-event.js b/ghost/admin/app/helpers/parse-member-event.js index 9c30484662..a8bc0a4929 100644 --- a/ghost/admin/app/helpers/parse-member-event.js +++ b/ghost/admin/app/helpers/parse-member-event.js @@ -84,6 +84,10 @@ export default class ParseMemberEventHelper extends Helper { icon = 'email-delivery-failed'; } + if (event.type === 'email_complaint_event') { + icon = 'email-delivery-spam'; + } + if (event.type === 'comment_event') { icon = 'comment'; } @@ -158,7 +162,11 @@ export default class ParseMemberEventHelper extends Helper { } if (event.type === 'email_failed_event') { - return 'failed to receive email'; + return this.feature.get('suppressionList') ? 'bounced email' : 'failed to receive email'; + } + + if (event.type === 'email_complaint_event') { + return 'flagged as spam email'; } if (event.type === 'comment_event') { diff --git a/ghost/admin/app/templates/members-activity.hbs b/ghost/admin/app/templates/members-activity.hbs index 1e9044a054..a08401f9b6 100644 --- a/ghost/admin/app/templates/members-activity.hbs +++ b/ghost/admin/app/templates/members-activity.hbs @@ -30,12 +30,12 @@
- {{#let (members-event-fetcher filter=(members-event-filter excludedEvents=this.fullExcludedEvents member=this.member) pageSize=50) as |eventsFetcher|}} + {{#let (members-event-fetcher filter=(members-event-filter excludedEvents=this.fullExcludedEvents member=this.member) pageSize=50 memberId=this.member) as |eventsFetcher|}} {{#if eventsFetcher.data}} {{#if this.memberRecord}} {{/if}} -
+
{{#if (not (or eventsFetcher.isLoading eventsFetcher.hasReachedEnd))}} diff --git a/ghost/admin/public/assets/icons/event-email-delivery-spam--feature-attribution.svg b/ghost/admin/public/assets/icons/event-email-delivery-spam--feature-attribution.svg new file mode 100644 index 0000000000..26952b53e3 --- /dev/null +++ b/ghost/admin/public/assets/icons/event-email-delivery-spam--feature-attribution.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ghost/admin/public/assets/icons/event-email-delivery-spam.svg b/ghost/admin/public/assets/icons/event-email-delivery-spam.svg new file mode 100644 index 0000000000..26952b53e3 --- /dev/null +++ b/ghost/admin/public/assets/icons/event-email-delivery-spam.svg @@ -0,0 +1,5 @@ + + + + +