2022-01-24 20:53:10 +03:00
const errors = require ( '@tryghost/errors' ) ;
2022-07-21 13:38:09 +03:00
const nql = require ( '@tryghost/nql' ) ;
2022-10-27 13:13:24 +03:00
const mingo = require ( 'mingo' ) ;
const { replaceFilters , expandFilters , splitFilter , getUsedKeys , chainTransformers , mapKeys } = require ( '@tryghost/mongo-utils' ) ;
/ * *
* This mongo transformer ignores the provided filter option and replaces the filter with a custom filter that was provided to the transformer . Allowing us to set a mongo filter instead of a string based NQL filter .
* /
function replaceCustomFilterTransformer ( filter ) {
// Instead of adding an existing filter, we replace a filter, because mongo transformers are only applied if there is any filter (so not executed for empty filters)
return function ( existingFilter ) {
return replaceFilters ( existingFilter , {
custom : filter
} ) ;
} ;
}
2022-01-21 13:16:24 +03:00
2021-02-15 17:16:58 +03:00
module . exports = class EventRepository {
constructor ( {
2022-01-18 17:53:51 +03:00
EmailRecipient ,
2021-02-15 17:16:58 +03:00
MemberSubscribeEvent ,
MemberPaymentEvent ,
MemberStatusEvent ,
2021-02-18 14:16:39 +03:00
MemberLoginEvent ,
2022-08-24 17:11:25 +03:00
MemberCreatedEvent ,
SubscriptionCreatedEvent ,
2022-01-18 17:53:51 +03:00
MemberPaidSubscriptionEvent ,
2022-09-21 11:25:51 +03:00
MemberLinkClickEvent ,
2022-10-17 16:44:18 +03:00
MemberFeedback ,
2022-07-25 18:48:23 +03:00
Comment ,
2022-08-24 17:11:25 +03:00
labsService ,
memberAttributionService
2021-02-15 17:16:58 +03:00
} ) {
this . _MemberSubscribeEvent = MemberSubscribeEvent ;
this . _MemberPaidSubscriptionEvent = MemberPaidSubscriptionEvent ;
this . _MemberPaymentEvent = MemberPaymentEvent ;
this . _MemberStatusEvent = MemberStatusEvent ;
2021-02-18 14:16:39 +03:00
this . _MemberLoginEvent = MemberLoginEvent ;
2022-01-18 17:53:51 +03:00
this . _EmailRecipient = EmailRecipient ;
2022-07-25 18:48:23 +03:00
this . _Comment = Comment ;
2022-01-18 17:53:51 +03:00
this . _labsService = labsService ;
2022-08-24 17:11:25 +03:00
this . _MemberCreatedEvent = MemberCreatedEvent ;
this . _SubscriptionCreatedEvent = SubscriptionCreatedEvent ;
2022-09-21 11:25:51 +03:00
this . _MemberLinkClickEvent = MemberLinkClickEvent ;
2022-10-17 16:44:18 +03:00
this . _MemberFeedback = MemberFeedback ;
2022-08-24 17:11:25 +03:00
this . _memberAttributionService = memberAttributionService ;
2021-02-15 17:16:58 +03:00
}
2022-09-21 11:25:51 +03:00
async getEventTimeline ( options = { } ) {
if ( ! options . limit ) {
options . limit = 10 ;
}
2022-10-27 13:13:24 +03:00
const [ typeFilter , otherFilter ] = this . getNQLSubset ( options . filter ) ;
2022-09-21 11:25:51 +03:00
// Changing this order might need a change in the query functions
// because of the different underlying models.
2022-10-27 13:13:24 +03:00
options . order = 'created_at desc, id desc' ;
2022-09-21 11:25:51 +03:00
// Create a list of all events that can be queried
const pageActions = [
2022-10-07 15:27:57 +03:00
{ type : 'comment_event' , action : 'getCommentEvents' } ,
2022-10-18 16:52:04 +03:00
{ type : 'click_event' , action : 'getClickEvents' } ,
{ type : 'signup_event' , action : 'getSignupEvents' } ,
{ type : 'subscription_event' , action : 'getSubscriptionEvents' }
2022-09-21 11:25:51 +03:00
] ;
2022-10-18 16:52:04 +03:00
// Some events are not filterable by post_id
2022-10-27 13:13:24 +03:00
if ( ! getUsedKeys ( otherFilter ) . includes ( 'data.post_id' ) ) {
2022-10-18 16:52:04 +03:00
pageActions . push (
{ type : 'newsletter_event' , action : 'getNewsletterSubscriptionEvents' } ,
{ type : 'login_event' , action : 'getLoginEvents' } ,
{ type : 'payment_event' , action : 'getPaymentEvents' }
) ;
}
2022-09-21 11:25:51 +03:00
if ( this . _EmailRecipient ) {
2022-10-24 12:11:44 +03:00
pageActions . push ( { type : 'email_sent_event' , action : 'getEmailSentEvents' } ) ;
2022-09-21 11:25:51 +03:00
pageActions . push ( { type : 'email_delivered_event' , action : 'getEmailDeliveredEvents' } ) ;
pageActions . push ( { type : 'email_opened_event' , action : 'getEmailOpenedEvents' } ) ;
pageActions . push ( { type : 'email_failed_event' , action : 'getEmailFailedEvents' } ) ;
}
2022-10-17 16:44:18 +03:00
if ( this . _labsService . isSet ( 'audienceFeedback' ) ) {
pageActions . push ( { type : 'feedback_event' , action : 'getFeedbackEvents' } ) ;
}
2022-09-21 11:25:51 +03:00
//Filter events to query
2022-10-27 13:13:24 +03:00
let filteredPages = pageActions ;
if ( typeFilter ) {
// Ideally we should be able to create a NQL filter without having a string
const query = new mingo . Query ( typeFilter ) ;
filteredPages = filteredPages . filter ( page => query . test ( page ) ) ;
}
2022-09-21 11:25:51 +03:00
//Start the promises
2022-10-27 13:13:24 +03:00
const pages = filteredPages . map ( ( page ) => {
return this [ page . action ] ( options , otherFilter ) ;
} ) ;
2022-09-21 11:25:51 +03:00
const allEventPages = await Promise . all ( pages ) ;
2022-10-18 16:52:04 +03:00
const allEvents = allEventPages . flatMap ( page => page . data ) ;
const totalEvents = allEventPages . reduce ( ( accumulator , page ) => accumulator + page . meta . pagination . total , 0 ) ;
2022-09-21 11:25:51 +03:00
2022-10-18 16:52:04 +03:00
return {
events : allEvents . sort (
( a , b ) => {
2022-10-27 13:13:24 +03:00
const diff = new Date ( b . data . created _at ) . getTime ( ) - new Date ( a . data . created _at ) . getTime ( ) ;
if ( diff !== 0 ) {
return diff ;
}
return b . data . id . localeCompare ( a . data . id ) ;
2022-10-18 16:52:04 +03:00
}
) . slice ( 0 , options . limit ) ,
meta : {
pagination : {
limit : options . limit ,
total : totalEvents ,
pages : options . limit > 0 ? Math . ceil ( totalEvents / options . limit ) : null ,
// Other values are unavailable (not possible to calculate easily)
page : null ,
next : null ,
prev : null
}
}
} ;
2022-09-21 11:25:51 +03:00
}
2021-02-15 17:16:58 +03:00
async registerPayment ( data ) {
await this . _MemberPaymentEvent . add ( {
... data ,
source : 'stripe'
} ) ;
}
2022-10-27 13:13:24 +03:00
async getNewsletterSubscriptionEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
2022-04-26 15:18:34 +03:00
withRelated : [ 'member' , 'newsletter' ] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.source' : 'source' ,
'data.member_id' : 'member_id'
} )
)
2022-01-21 19:56:15 +03:00
} ;
2022-01-25 14:20:34 +03:00
2021-02-18 14:16:39 +03:00
const { data : models , meta } = await this . _MemberSubscribeEvent . findPage ( options ) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2021-02-18 14:16:39 +03:00
return {
type : 'newsletter_event' ,
2022-01-25 18:44:29 +03:00
data : model . toJSON ( options )
2021-02-18 14:16:39 +03:00
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getSubscriptionEvents ( options = { } , filter ) {
2022-08-24 17:11:25 +03:00
if ( ! this . _labsService . isSet ( 'memberAttribution' ) ) {
options = {
... options ,
withRelated : [ 'member' ] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id'
} )
)
2022-08-24 17:11:25 +03:00
} ;
const { data : models , meta } = await this . _MemberPaidSubscriptionEvent . findPage ( options ) ;
const data = models . map ( ( model ) => {
return {
type : 'subscription_event' ,
data : model . toJSON ( options )
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-01-21 19:56:15 +03:00
options = {
... options ,
2022-10-27 12:44:19 +03:00
withRelated : [
'member' ,
'subscriptionCreatedEvent.postAttribution' ,
'subscriptionCreatedEvent.userAttribution' ,
'subscriptionCreatedEvent.tagAttribution' ,
'subscriptionCreatedEvent.memberCreatedEvent' ,
// This is rediculous, but we need the tier name (we'll be able to shorten this later when we switch to the subscriptions table)
'stripeSubscription.stripePrice.stripeProduct.product'
] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id'
} ) ,
( f ) => {
// Special one: when data.post_id is used, replace it with two filters: subscriptionCreatedEvent.attribution_id:x+subscriptionCreatedEvent.attribution_type:post
return expandFilters ( f , [ {
key : 'data.post_id' ,
replacement : 'subscriptionCreatedEvent.attribution_id' ,
expansion : { 'subscriptionCreatedEvent.attribution_type' : 'post' }
} ] ) ;
}
)
2022-01-21 19:56:15 +03:00
} ;
2022-01-25 14:20:34 +03:00
2021-02-18 14:16:39 +03:00
const { data : models , meta } = await this . _MemberPaidSubscriptionEvent . findPage ( options ) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2022-10-27 12:44:19 +03:00
const d = {
... model . toJSON ( options ) ,
attribution : model . get ( 'type' ) === 'created' && model . related ( 'subscriptionCreatedEvent' ) && model . related ( 'subscriptionCreatedEvent' ) . id ? this . _memberAttributionService . getEventAttribution ( model . related ( 'subscriptionCreatedEvent' ) ) : null ,
signup : model . get ( 'type' ) === 'created' && model . related ( 'subscriptionCreatedEvent' ) && model . related ( 'subscriptionCreatedEvent' ) . id && model . related ( 'subscriptionCreatedEvent' ) . related ( 'memberCreatedEvent' ) && model . related ( 'subscriptionCreatedEvent' ) . related ( 'memberCreatedEvent' ) . id ? true : false ,
tierName : model . related ( 'stripeSubscription' ) && model . related ( 'stripeSubscription' ) . related ( 'stripePrice' ) && model . related ( 'stripeSubscription' ) . related ( 'stripePrice' ) . related ( 'stripeProduct' ) && model . related ( 'stripeSubscription' ) . related ( 'stripePrice' ) . related ( 'stripeProduct' ) . related ( 'product' ) ? model . related ( 'stripeSubscription' ) . related ( 'stripePrice' ) . related ( 'stripeProduct' ) . related ( 'product' ) . get ( 'name' ) : null
} ;
delete d . stripeSubscription ;
2021-02-18 14:16:39 +03:00
return {
type : 'subscription_event' ,
2022-10-27 12:44:19 +03:00
data : d
2021-02-18 14:16:39 +03:00
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getPaymentEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
withRelated : [ 'member' ] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id'
} )
)
2022-01-21 19:56:15 +03:00
} ;
2022-01-25 14:20:34 +03:00
2021-02-18 14:16:39 +03:00
const { data : models , meta } = await this . _MemberPaymentEvent . findPage ( options ) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2021-02-18 14:16:39 +03:00
return {
type : 'payment_event' ,
2022-01-25 18:44:29 +03:00
data : model . toJSON ( options )
2021-02-18 14:16:39 +03:00
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getLoginEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
withRelated : [ 'member' ] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id'
} )
)
2022-01-21 19:56:15 +03:00
} ;
2022-01-25 14:20:34 +03:00
2021-02-18 14:16:39 +03:00
const { data : models , meta } = await this . _MemberLoginEvent . findPage ( options ) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2021-02-18 14:16:39 +03:00
return {
type : 'login_event' ,
2022-01-25 18:44:29 +03:00
data : model . toJSON ( options )
2021-02-18 14:16:39 +03:00
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getSignupEvents ( options = { } , filter ) {
2022-08-24 17:11:25 +03:00
if ( ! this . _labsService . isSet ( 'memberAttribution' ) ) {
options = {
... options ,
withRelated : [ 'member' ] ,
2022-10-27 13:13:24 +03:00
filter : 'from_status:null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id'
} )
)
2022-08-24 17:11:25 +03:00
} ;
const { data : models , meta } = await this . _MemberStatusEvent . findPage ( options ) ;
const data = models . map ( ( model ) => {
return {
type : 'signup_event' ,
data : model . toJSON ( options )
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
return this . getCreatedEvents ( options , filter ) ;
2022-10-06 08:50:27 +03:00
}
2022-10-27 13:13:24 +03:00
async getCreatedEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
2022-10-27 12:44:19 +03:00
withRelated : [
'member' ,
'postAttribution' ,
'userAttribution' ,
'tagAttribution'
] ,
2022-10-27 13:13:24 +03:00
filter : 'subscriptionCreatedEvent.id:null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id' ,
'data.source' : 'source'
} ) ,
( f ) => {
// Special one: when data.post_id is used, replace it with two filters: attribution_id:x+attribution_type:post
return expandFilters ( f , [ {
key : 'data.post_id' ,
replacement : 'attribution_id' ,
expansion : { attribution _type : 'post' }
} ] ) ;
}
)
2022-01-21 19:56:15 +03:00
} ;
2022-01-25 14:20:34 +03:00
2022-08-24 17:11:25 +03:00
const { data : models , meta } = await this . _MemberCreatedEvent . findPage ( options ) ;
2021-03-05 15:38:30 +03:00
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2021-03-05 15:38:30 +03:00
return {
type : 'signup_event' ,
2022-08-24 17:11:25 +03:00
data : {
... model . toJSON ( options ) ,
attribution : this . _memberAttributionService . getEventAttribution ( model )
}
2021-03-05 15:38:30 +03:00
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getCommentEvents ( options = { } , filter ) {
2022-07-25 18:48:23 +03:00
options = {
... options ,
withRelated : [ 'member' , 'post' , 'parent' ] ,
2022-10-27 13:13:24 +03:00
filter : 'member_id:-null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'post_id'
} )
)
2022-07-25 18:48:23 +03:00
} ;
const { data : models , meta } = await this . _Comment . findPage ( options ) ;
const data = models . map ( ( model ) => {
return {
type : 'comment_event' ,
data : model . toJSON ( options )
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getClickEvents ( options = { } , filter ) {
2022-09-21 11:25:51 +03:00
options = {
... options ,
withRelated : [ 'member' , 'link' , 'link.post' ] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'post_id'
} )
)
2022-09-21 11:25:51 +03:00
} ;
const { data : models , meta } = await this . _MemberLinkClickEvent . findPage ( options ) ;
const data = models . map ( ( model ) => {
return {
type : 'click_event' ,
data : model . toJSON ( options )
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getFeedbackEvents ( options = { } , filter ) {
2022-10-17 16:44:18 +03:00
options = {
... options ,
withRelated : [ 'member' , 'post' ] ,
2022-10-27 13:13:24 +03:00
filter : 'custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'created_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'post_id'
} )
)
2022-10-17 16:44:18 +03:00
} ;
const { data : models , meta } = await this . _MemberFeedback . findPage ( options ) ;
const data = models . map ( ( model ) => {
return {
type : 'feedback_event' ,
data : model . toJSON ( options )
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getEmailSentEvents ( options = { } , filter ) {
2022-10-24 12:11:44 +03:00
options = {
... options ,
withRelated : [ 'member' , 'email' ] ,
2022-10-27 13:13:24 +03:00
filter : 'failed_at:null+processed_at:-null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'processed_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'email.post_id'
} )
)
2022-10-24 12:11:44 +03:00
} ;
options . order = options . order . replace ( /created_at/g , 'processed_at' ) ;
const { data : models , meta } = await this . _EmailRecipient . findPage (
options
) ;
const data = models . map ( ( model ) => {
return {
type : 'email_sent_event' ,
data : {
2022-10-27 13:13:24 +03:00
id : model . id ,
2022-10-24 12:11:44 +03:00
member _id : model . get ( 'member_id' ) ,
created _at : model . get ( 'processed_at' ) ,
member : model . related ( 'member' ) . toJSON ( ) ,
email : model . related ( 'email' ) . toJSON ( )
}
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getEmailDeliveredEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
withRelated : [ 'member' , 'email' ] ,
2022-10-27 13:13:24 +03:00
filter : 'delivered_at:-null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'delivered_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'email.post_id'
} )
)
2022-01-21 19:56:15 +03:00
} ;
2022-02-01 17:47:15 +03:00
options . order = options . order . replace ( /created_at/g , 'delivered_at' ) ;
2022-01-25 14:20:34 +03:00
2022-01-18 17:53:51 +03:00
const { data : models , meta } = await this . _EmailRecipient . findPage (
options
) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2022-01-18 17:53:51 +03:00
return {
type : 'email_delivered_event' ,
data : {
2022-10-27 13:13:24 +03:00
id : model . id ,
2022-01-25 18:44:29 +03:00
member _id : model . get ( 'member_id' ) ,
created _at : model . get ( 'delivered_at' ) ,
member : model . related ( 'member' ) . toJSON ( ) ,
email : model . related ( 'email' ) . toJSON ( )
2022-01-18 17:53:51 +03:00
}
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getEmailOpenedEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
withRelated : [ 'member' , 'email' ] ,
2022-10-27 13:13:24 +03:00
filter : 'opened_at:-null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'opened_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'email.post_id'
} )
)
2022-01-21 19:56:15 +03:00
} ;
2022-02-01 17:47:15 +03:00
options . order = options . order . replace ( /created_at/g , 'opened_at' ) ;
2022-01-25 14:20:34 +03:00
2022-01-18 17:53:51 +03:00
const { data : models , meta } = await this . _EmailRecipient . findPage (
options
) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2022-01-18 17:53:51 +03:00
return {
type : 'email_opened_event' ,
data : {
2022-10-27 13:13:24 +03:00
id : model . id ,
2022-01-25 18:44:29 +03:00
member _id : model . get ( 'member_id' ) ,
created _at : model . get ( 'opened_at' ) ,
member : model . related ( 'member' ) . toJSON ( ) ,
email : model . related ( 'email' ) . toJSON ( )
2022-01-18 17:53:51 +03:00
}
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-10-27 13:13:24 +03:00
async getEmailFailedEvents ( options = { } , filter ) {
2022-01-21 19:56:15 +03:00
options = {
... options ,
withRelated : [ 'member' , 'email' ] ,
2022-10-27 13:13:24 +03:00
filter : 'failed_at:-null+custom:true' ,
mongoTransformer : chainTransformers (
// First set the filter manually
replaceCustomFilterTransformer ( filter ) ,
// Map the used keys in that filter
... mapKeys ( {
'data.created_at' : 'failed_at' ,
'data.member_id' : 'member_id' ,
'data.post_id' : 'email.post_id'
} )
)
2022-01-21 19:56:15 +03:00
} ;
2022-02-01 17:47:15 +03:00
options . order = options . order . replace ( /created_at/g , 'failed_at' ) ;
2022-01-25 14:20:34 +03:00
2022-01-18 17:53:51 +03:00
const { data : models , meta } = await this . _EmailRecipient . findPage (
options
) ;
2022-01-25 18:44:29 +03:00
const data = models . map ( ( model ) => {
2022-01-18 17:53:51 +03:00
return {
type : 'email_failed_event' ,
data : {
2022-10-27 13:13:24 +03:00
id : model . id ,
2022-01-25 18:44:29 +03:00
member _id : model . get ( 'member_id' ) ,
created _at : model . get ( 'failed_at' ) ,
member : model . related ( 'member' ) . toJSON ( ) ,
email : model . related ( 'email' ) . toJSON ( )
2022-01-18 17:53:51 +03:00
}
} ;
} ) ;
return {
data ,
meta
} ;
}
2022-01-24 20:53:10 +03:00
/ * *
2022-10-27 13:13:24 +03:00
* Split the filter in two parts :
* - One with 'type' that will be applied to all the pages
* - Other filter that will be applied to each individual page
*
* Throws if splitting is not possible ( e . g . OR ' ing type with other filters )
2022-01-24 20:53:10 +03:00
* /
getNQLSubset ( filter ) {
if ( ! filter ) {
2022-10-27 13:13:24 +03:00
return [ undefined , undefined ] ;
2022-01-24 20:53:10 +03:00
}
2022-10-27 13:13:24 +03:00
const allowList = [ 'data.created_at' , 'data.member_id' , 'data.post_id' , 'type' , 'id' ] ;
const parsed = nql ( filter ) . parse ( ) ;
const keys = getUsedKeys ( parsed ) ;
2022-01-24 20:53:10 +03:00
2022-10-27 13:13:24 +03:00
for ( const key of keys ) {
if ( ! allowList . includes ( key ) ) {
throw new errors . IncorrectUsageError ( {
message : 'Cannot filter by ' + key
} ) ;
}
2022-01-24 20:53:10 +03:00
}
2022-10-27 13:13:24 +03:00
try {
return splitFilter ( parsed , [ 'type' ] ) ;
} catch ( e ) {
2022-01-24 20:53:10 +03:00
throw new errors . IncorrectUsageError ( {
2022-10-27 13:13:24 +03:00
message : e . message
2022-01-24 20:53:10 +03:00
} ) ;
}
2021-02-15 17:16:58 +03:00
}
async getMRR ( ) {
const results = await this . _MemberPaidSubscriptionEvent . findAll ( {
aggregateMRRDeltas : true
} ) ;
const resultsJSON = results . toJSON ( ) ;
2022-01-25 18:44:29 +03:00
const cumulativeResults = resultsJSON . reduce ( ( accumulator , result ) => {
if ( ! accumulator [ result . currency ] ) {
2021-02-15 17:16:58 +03:00
return {
2022-01-25 18:44:29 +03:00
... accumulator ,
2021-02-15 17:16:58 +03:00
[ result . currency ] : [ {
date : result . date ,
mrr : result . mrr _delta ,
currency : result . currency
} ]
} ;
}
return {
2022-01-25 18:44:29 +03:00
... accumulator ,
[ result . currency ] : accumulator [ result . currency ] . concat ( [ {
2021-02-15 17:16:58 +03:00
date : result . date ,
2022-01-25 18:44:29 +03:00
mrr : result . mrr _delta + accumulator [ result . currency ] . slice ( - 1 ) [ 0 ] . mrr ,
2021-02-15 17:16:58 +03:00
currency : result . currency
} ] )
} ;
} , { } ) ;
return cumulativeResults ;
}
async getStatuses ( ) {
const results = await this . _MemberStatusEvent . findAll ( {
aggregateStatusCounts : true
} ) ;
const resultsJSON = results . toJSON ( ) ;
2022-01-25 18:44:29 +03:00
const cumulativeResults = resultsJSON . reduce ( ( accumulator , result , index ) => {
2021-02-15 17:16:58 +03:00
if ( index === 0 ) {
return [ {
date : result . date ,
paid : result . paid _delta ,
comped : result . comped _delta ,
free : result . free _delta
} ] ;
}
2022-01-25 18:44:29 +03:00
return accumulator . concat ( [ {
2021-02-15 17:16:58 +03:00
date : result . date ,
2022-01-25 18:44:29 +03:00
paid : result . paid _delta + accumulator [ index - 1 ] . paid ,
comped : result . comped _delta + accumulator [ index - 1 ] . comped ,
free : result . free _delta + accumulator [ index - 1 ] . free
2021-02-15 17:16:58 +03:00
} ] ) ;
} , [ ] ) ;
return cumulativeResults ;
}
} ;