2022-09-23 20:15:08 +03:00
|
|
|
import moment from 'moment-timezone';
|
2022-01-22 18:35:08 +03:00
|
|
|
import {Resource} from 'ember-could-get-used-to-this';
|
|
|
|
import {TrackedArray} from 'tracked-built-ins';
|
|
|
|
import {action} from '@ember/object';
|
|
|
|
import {inject as service} from '@ember/service';
|
2022-02-09 13:49:38 +03:00
|
|
|
import {task} from 'ember-concurrency';
|
2022-01-22 18:35:08 +03:00
|
|
|
import {tracked} from '@glimmer/tracking';
|
|
|
|
|
|
|
|
export default class MembersEventsFetcher extends Resource {
|
|
|
|
@service ajax;
|
|
|
|
@service ghostPaths;
|
2022-05-04 11:21:42 +03:00
|
|
|
@service store;
|
2022-11-18 13:33:48 +03:00
|
|
|
@service feature;
|
2022-01-22 18:35:08 +03:00
|
|
|
|
|
|
|
@tracked data = new TrackedArray([]);
|
|
|
|
@tracked isLoading = false;
|
|
|
|
@tracked isError = false;
|
2022-01-22 19:04:54 +03:00
|
|
|
@tracked errorMessage = null;
|
2022-01-22 18:35:08 +03:00
|
|
|
@tracked hasReachedEnd = false;
|
|
|
|
|
2022-09-23 20:15:08 +03:00
|
|
|
/**
|
2022-05-04 11:21:42 +03:00
|
|
|
* Keep track whether we have multiple newsletters (required for parsing events)
|
|
|
|
*/
|
|
|
|
@tracked hasMultipleNewsletters = null;
|
|
|
|
|
2022-01-22 18:35:08 +03:00
|
|
|
cursor = null;
|
|
|
|
|
|
|
|
get value() {
|
|
|
|
return {
|
|
|
|
isLoading: this.isLoading,
|
|
|
|
isError: this.isError,
|
2022-01-22 19:04:54 +03:00
|
|
|
errorMessage: this.errorMessage,
|
2022-01-22 18:35:08 +03:00
|
|
|
data: this.data,
|
|
|
|
loadNextPage: this.loadNextPage,
|
2022-05-04 11:21:42 +03:00
|
|
|
hasReachedEnd: this.hasReachedEnd,
|
|
|
|
hasMultipleNewsletters: this.hasMultipleNewsletters
|
2022-01-22 18:35:08 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async setup() {
|
|
|
|
this.cursor = moment.utc().format('YYYY-MM-DD HH:mm:ss');
|
2022-01-25 13:13:37 +03:00
|
|
|
let filter = `data.created_at:<'${this.cursor}'`;
|
2022-01-22 18:35:08 +03:00
|
|
|
|
|
|
|
if (this.args.named.filter) {
|
|
|
|
filter += `+${this.args.named.filter}`;
|
|
|
|
}
|
|
|
|
|
2022-05-04 11:21:42 +03:00
|
|
|
// Can't get this working with Promise.all, somehow results in an infinite loop
|
|
|
|
await this.loadEventsTask.perform({filter});
|
|
|
|
await this.loadMultipleNewslettersTask.perform();
|
2022-01-22 18:35:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
loadNextPage() {
|
|
|
|
// NOTE: assumes data is always ordered by created_at desc
|
|
|
|
const lastEvent = this.data[this.data.length - 1];
|
|
|
|
|
|
|
|
if (!lastEvent?.data?.created_at) {
|
|
|
|
this.hasReachedEnd = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const cursor = moment.utc(lastEvent.data.created_at).format('YYYY-MM-DD HH:mm:ss');
|
|
|
|
|
|
|
|
if (cursor === this.cursor) {
|
|
|
|
this.hasReachedEnd = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.cursor = cursor;
|
2022-01-25 13:13:37 +03:00
|
|
|
let filter = `data.created_at:<'${this.cursor}'`;
|
2022-01-22 18:35:08 +03:00
|
|
|
|
|
|
|
if (this.args.named.filter) {
|
|
|
|
filter += `+${this.args.named.filter}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.loadEventsTask.perform({filter});
|
|
|
|
}
|
|
|
|
|
2022-05-04 11:21:42 +03:00
|
|
|
/**
|
|
|
|
* We need to know whether we have multiple newsletters so we can hide/show the newsletter name
|
|
|
|
*/
|
|
|
|
@task
|
|
|
|
*loadMultipleNewslettersTask() {
|
|
|
|
try {
|
|
|
|
const res = yield this.store.query('newsletter', {filter: 'status:active', include: 'none', limit: 1});
|
|
|
|
const newsletterCount = res.meta.pagination.total;
|
|
|
|
this.hasMultipleNewsletters = newsletterCount > 1;
|
|
|
|
} catch (e) {
|
|
|
|
// Default to true (harms the least)
|
|
|
|
this.hasMultipleNewsletters = true;
|
|
|
|
console.error(e); // eslint-disable-line
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-22 18:35:08 +03:00
|
|
|
@task
|
|
|
|
*loadEventsTask(queryParams) {
|
|
|
|
try {
|
|
|
|
this.isLoading = true;
|
|
|
|
|
|
|
|
const url = this.ghostPaths.url.api('members/events');
|
|
|
|
const data = Object.assign({}, queryParams, {limit: this.args.named.pageSize});
|
|
|
|
const {events} = yield this.ajax.request(url, {data});
|
|
|
|
|
|
|
|
if (events.length < data.limit) {
|
|
|
|
this.hasReachedEnd = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.data.push(...events);
|
2022-11-18 13:33:48 +03:00
|
|
|
|
|
|
|
// 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'));
|
|
|
|
}
|
|
|
|
}
|
2022-01-22 18:35:08 +03:00
|
|
|
} catch (e) {
|
|
|
|
this.isError = true;
|
2022-01-22 19:04:54 +03:00
|
|
|
|
|
|
|
const errorMessage = e.payload?.errors?.[0]?.message;
|
|
|
|
if (errorMessage) {
|
|
|
|
this.errorMessage = errorMessage;
|
|
|
|
}
|
|
|
|
|
2022-01-22 18:35:08 +03:00
|
|
|
// TODO: log to Sentry
|
|
|
|
console.error(e); // eslint-disable-line
|
|
|
|
} finally {
|
|
|
|
this.isLoading = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-18 13:33:48 +03:00
|
|
|
|
|
|
|
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"<localhost@example.com>',
|
|
|
|
reply_to: 'noreply@localhost',
|
|
|
|
html: '<!doctype html>\n<html>\n\n<head>\n<meta name="viewport" content="width=device-width">\n<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n<!--[if mso]><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch><o:AllowPNG/></o:OfficeDocumentSettings></xml><![endif]-->\n<title>Spam test</title>\n<style>\n.post-title-link {\n color: #15212A;\n display: block;\n text-align: center;\n margin-top: 50px;\n}\n.post-title-link-left {\n text-align: left;\n}\n.view-online-link {\n word-wrap: none;\n white-space: nowrap;\n color: #15212A;\n}\n.kg-nft-link {\n display: block;\n text-decoration: none !important;\n color: #15212A !important;\n font-family: inherit !important;\n font-size: 14px;\n line-height: 1.3em;\n padding-top: 4px;\n padding-right: 20px;\n padding-left: 20px;\n padding-bottom: 4px;\n}\n.kg-twitter-link {\n display: block;\n text-decoration: none !important;\n color: #15212A !important;\n font-family: inherit !important;\n font-size: 15px;\n padding: 8px;\n line-height: 1.3em;\n}\n@media only screen and (max-width: 620px) {\n table.body {\n width: 100%;\n min-width: 100%;\n }\n\n table.body p,\ntable.body ul,\ntable.body ol,\ntable.body td,\ntable.body span {\n font-size: 16px !important;\n }\n\n table.body pre {\n white-space: pre-wrap !important;\n word-break: break-word !important;\n }\n\n table.body .wrapper,\ntable.body .article {\n padding: 0 10px !important;\n }\n\n table.body .content {\n padding: 0 !important;\n }\n\n table.body .container {\n padding: 0 !important;\n width: 100% !important;\n }\n\n table.body .main {\n border-left-width: 0 !important;\n border-radius: 0 !important;\n border-right-width: 0 !important;\n }\n\n table.body .btn table {\n width: 100% !important;\n }\n\n table.body .btn a {\n width: 100% !important;\n }\n\n table.body .img-responsive {\n height: auto !important;\n max-width: 100% !important;\n width: auto !important;\n }\n\n table.body .site-icon img {\n width: 40px !important;\n height: 40px !important;\n }\n\n table.body .site-url a {\n font-size: 14px !important;\n padding-bottom: 15px !important;\n }\n\n table.body .post-meta {\n white-space: normal !important;\n font-size: 12px !important;\n line-height: 1.5em;\n }\n\n table.body .view-online-link,\ntable.body .footer,\ntable.body .footer a {\n font-size: 12px !important;\n }\n\n table.body .post-title a {\n font-size: 32px !important;\n line-height: 1.15em !important;\n }\n\n table.body .kg-bookmark-card {\n width: 90vw !important;\n }\n\n table.body .kg-bookmark-thumbnail {\n display: none !important;\n }\n\n table.body .kg-bookmark-metadata span {\n font-size: 13px !important;\n }\n\n table.body .kg-embed-card {\n max-width: 90vw !important;\n }\n\n table.body h1 {\n font-size: 32px !important;\n line-height: 1.3em !important;\n }\n\n table.body h2 {\n font-size: 26px !important;\n line-height: 1.22em !important;\n }\n\n table.body h3 {\n font-size: 21px !important;\n line-height: 1.25em !important;\n }\n\n table.body h4 {\n font-size: 19px !important;\n line-height: 1.3em !important;\n }\n\n table.body h5 {\n font-size: 16px !important;\n line-height: 1.4em !important;\n }\n\n table.body h6 {\n font-size: 16px !important;\n line-height: 1.4em !important;\n }\n\n table.body blockquote {\n font-size: 17px;\n line-height: 1.6em;\n margin-bottom: 0;\n padding-left: 15px;\n }\n\n table.body blockquote.kg-blockquote-alt {\n border-left: 0 none !important;\n margin: 0 0 2.5em 0 !important;\n padding: 0 50px 0 50px !important;\n font-size: 1.2em;\n }\n\n table.body blockquote + * {\n margin-top: 1.5em !important;\n }\n\n table.body hr {\n margin: 2em 0 !important;\n }\n\n table.body figcaption,\ntable.body figcaption a {\n font-size: 13px !important;\n }\n}\n@media all {\n .ExternalClass {\n width: 100%;\n }\n\n .ExternalClass,
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|