mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Added donation events to activity feeds (#17632)
fixes TryGhost/Product#3698 fixes TryGhost/Product#3699
This commit is contained in:
parent
374bfc405c
commit
874552bdbe
@ -93,8 +93,18 @@
|
|||||||
{{#let (parse-member-event event eventsFetcher.hasMultipleNewsletters) as |parsedEvent|}}
|
{{#let (parse-member-event event eventsFetcher.hasMultipleNewsletters) as |parsedEvent|}}
|
||||||
<div class="gh-dashboard-list-item member-details">
|
<div class="gh-dashboard-list-item member-details">
|
||||||
<div class="gh-dashboard-list-item-sub">
|
<div class="gh-dashboard-list-item-sub">
|
||||||
<GhMemberAvatar @member={{parsedEvent.member}} @containerClass="w8 h8 mr3 flex-shrink-0" />
|
{{#if parsedEvent.member}}
|
||||||
<LinkTo class="gh-dashboard-list-text" @route="member" @model="{{parsedEvent.memberId}}" data-test-dashboard-member-activity-item>{{parsedEvent.subject}}</LinkTo>
|
<GhMemberAvatar @member={{parsedEvent.member}} @containerClass="w8 h8 mr3 flex-shrink-0" />
|
||||||
|
<LinkTo class="gh-dashboard-list-text" @route="member" @model="{{parsedEvent.memberId}}" data-test-dashboard-member-activity-item>{{parsedEvent.subject}}</LinkTo>
|
||||||
|
{{else}}
|
||||||
|
{{#if parsedEvent.email}}
|
||||||
|
<GhMemberAvatar @name={{parsedEvent.subject}} @containerClass="w8 h8 mr3 flex-shrink-0" />
|
||||||
|
<a class="gh-dashboard-list-text" href="mailto:{{parsedEvent.email}}" target="_blank" rel="noopener noreferrer" title="{{parsedEvent.email}}">{{parsedEvent.subject}}</a>
|
||||||
|
{{else}}
|
||||||
|
<GhMemberAvatar @name={{parsedEvent.subject}} @containerClass="w8 h8 mr3 flex-shrink-0" />
|
||||||
|
<span class="gh-dashboard-list-text">{{parsedEvent.subject}}</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="gh-dashboard-list-item-sub">
|
<div class="gh-dashboard-list-item-sub">
|
||||||
{{svg-jar parsedEvent.icon }}
|
{{svg-jar parsedEvent.icon }}
|
||||||
|
@ -13,9 +13,9 @@ const stringToHslColor = function (str, saturation, lightness) {
|
|||||||
|
|
||||||
export default class GhMemberAvatarComponent extends Component {
|
export default class GhMemberAvatarComponent extends Component {
|
||||||
get memberName() {
|
get memberName() {
|
||||||
let {member} = this.args;
|
let {member, name} = this.args;
|
||||||
|
|
||||||
return member?.name || member?.email || 'NM';
|
return member?.name || member?.email || name || 'NM';
|
||||||
}
|
}
|
||||||
|
|
||||||
get avatarImage() {
|
get avatarImage() {
|
||||||
|
@ -45,8 +45,18 @@
|
|||||||
{{#let (parse-member-event event) as |parsedEvent|}}
|
{{#let (parse-member-event event) as |parsedEvent|}}
|
||||||
<div class="gh-dashboard-list-item">
|
<div class="gh-dashboard-list-item">
|
||||||
<div class="gh-dashboard-list-item-sub">
|
<div class="gh-dashboard-list-item-sub">
|
||||||
<GhMemberAvatar @member={{parsedEvent.member}} @containerClass="w6 h6 mr3 flex-shrink-0" />
|
{{#if parsedEvent.member}}
|
||||||
<LinkTo class="gh-dashboard-list-text" @route="member" @model="{{parsedEvent.memberId}}" @query={{hash postAnalytics=@post.id}}>{{parsedEvent.subject}}</LinkTo>
|
<GhMemberAvatar @member={{parsedEvent.member}} @containerClass="w6 h6 mr3 flex-shrink-0" />
|
||||||
|
<LinkTo class="gh-dashboard-list-text" @route="member" @model="{{parsedEvent.memberId}}" @query={{hash postAnalytics=@post.id}}>{{parsedEvent.subject}}</LinkTo>
|
||||||
|
{{else}}
|
||||||
|
{{#if parsedEvent.email}}
|
||||||
|
<GhMemberAvatar @name={{parsedEvent.subject}} @containerClass="w6 h6 mr3 flex-shrink-0" />
|
||||||
|
<a class="gh-dashboard-list-text" href="mailto:{{parsedEvent.email}}" target="_blank" rel="noopener noreferrer" title="{{parsedEvent.email}}">{{parsedEvent.subject}}</a>
|
||||||
|
{{else}}
|
||||||
|
<GhMemberAvatar @name={{parsedEvent.subject}} @containerClass="w6 h6 mr3 flex-shrink-0" />
|
||||||
|
<span class="gh-dashboard-list-text">{{parsedEvent.subject}}</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="gh-dashboard-list-item-sub">
|
<div class="gh-dashboard-list-item-sub">
|
||||||
{{svg-jar parsedEvent.icon }}
|
{{svg-jar parsedEvent.icon }}
|
||||||
|
@ -10,7 +10,7 @@ export default class ParseMemberEventHelper extends Helper {
|
|||||||
@service membersUtils;
|
@service membersUtils;
|
||||||
|
|
||||||
compute([event, hasMultipleNewsletters]) {
|
compute([event, hasMultipleNewsletters]) {
|
||||||
const subject = event.data.member.name || event.data.member.email;
|
const subject = event.data.member ? (event.data.member.name || event.data.member.email) : (event.data.name || event.data.email || '');
|
||||||
const icon = this.getIcon(event);
|
const icon = this.getIcon(event);
|
||||||
const action = this.getAction(event, hasMultipleNewsletters);
|
const action = this.getAction(event, hasMultipleNewsletters);
|
||||||
const info = this.getInfo(event);
|
const info = this.getInfo(event);
|
||||||
@ -110,6 +110,10 @@ export default class ParseMemberEventHelper extends Helper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.type === 'donation_event') {
|
||||||
|
icon = 'subscriptions';
|
||||||
|
}
|
||||||
|
|
||||||
return 'event-' + icon;
|
return 'event-' + icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +207,10 @@ export default class ParseMemberEventHelper extends Helper {
|
|||||||
}
|
}
|
||||||
return 'less like this';
|
return 'less like this';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.type === 'donation_event') {
|
||||||
|
return `Made a one-time payment`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -222,7 +230,7 @@ export default class ParseMemberEventHelper extends Helper {
|
|||||||
* Clickable object, shown between action and info, or in a separate column in some views
|
* Clickable object, shown between action and info, or in a separate column in some views
|
||||||
*/
|
*/
|
||||||
getObject(event) {
|
getObject(event) {
|
||||||
if (event.type === 'signup_event' || event.type === 'subscription_event') {
|
if (event.type === 'signup_event' || event.type === 'subscription_event' || event.type === 'donation_event') {
|
||||||
if (event.data.attribution?.title) {
|
if (event.data.attribution?.title) {
|
||||||
return event.data.attribution.title;
|
return event.data.attribution.title;
|
||||||
}
|
}
|
||||||
@ -278,6 +286,12 @@ export default class ParseMemberEventHelper extends Helper {
|
|||||||
return 'Free';
|
return 'Free';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.type === 'donation_event') {
|
||||||
|
const symbol = getSymbol(event.data.currency);
|
||||||
|
const formattedAmount = symbol + getNonDecimal(event.data.amount, event.data.currency);
|
||||||
|
return formattedAmount;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +318,7 @@ export default class ParseMemberEventHelper extends Helper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['signup_event', 'subscription_event'].includes(event.type)) {
|
if (['signup_event', 'subscription_event', 'donation_event'].includes(event.type)) {
|
||||||
if (event.data.attribution && event.data.attribution.url) {
|
if (event.data.attribution && event.data.attribution.url) {
|
||||||
return event.data.attribution.url;
|
return event.data.attribution.url;
|
||||||
}
|
}
|
||||||
|
@ -182,6 +182,7 @@ function createApiInstance(config) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
models: {
|
models: {
|
||||||
|
DonationPaymentEvent: models.DonationPaymentEvent,
|
||||||
EmailRecipient: models.EmailRecipient,
|
EmailRecipient: models.EmailRecipient,
|
||||||
StripeCustomer: models.MemberStripeCustomer,
|
StripeCustomer: models.MemberStripeCustomer,
|
||||||
StripeCustomerSubscription: models.StripeCustomerSubscription,
|
StripeCustomerSubscription: models.StripeCustomerSubscription,
|
||||||
|
@ -37,6 +37,7 @@ module.exports = function MembersAPI({
|
|||||||
getSubject
|
getSubject
|
||||||
},
|
},
|
||||||
models: {
|
models: {
|
||||||
|
DonationPaymentEvent,
|
||||||
EmailRecipient,
|
EmailRecipient,
|
||||||
StripeCustomer,
|
StripeCustomer,
|
||||||
StripeCustomerSubscription,
|
StripeCustomerSubscription,
|
||||||
@ -107,6 +108,7 @@ module.exports = function MembersAPI({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const eventRepository = new EventRepository({
|
const eventRepository = new EventRepository({
|
||||||
|
DonationPaymentEvent,
|
||||||
EmailRecipient,
|
EmailRecipient,
|
||||||
MemberSubscribeEvent,
|
MemberSubscribeEvent,
|
||||||
MemberPaidSubscriptionEvent,
|
MemberPaidSubscriptionEvent,
|
||||||
|
@ -17,6 +17,7 @@ function replaceCustomFilterTransformer(filter) {
|
|||||||
|
|
||||||
module.exports = class EventRepository {
|
module.exports = class EventRepository {
|
||||||
constructor({
|
constructor({
|
||||||
|
DonationPaymentEvent,
|
||||||
EmailRecipient,
|
EmailRecipient,
|
||||||
MemberSubscribeEvent,
|
MemberSubscribeEvent,
|
||||||
MemberPaymentEvent,
|
MemberPaymentEvent,
|
||||||
@ -32,6 +33,7 @@ module.exports = class EventRepository {
|
|||||||
labsService,
|
labsService,
|
||||||
memberAttributionService
|
memberAttributionService
|
||||||
}) {
|
}) {
|
||||||
|
this._DonationPaymentEvent = DonationPaymentEvent;
|
||||||
this._MemberSubscribeEvent = MemberSubscribeEvent;
|
this._MemberSubscribeEvent = MemberSubscribeEvent;
|
||||||
this._MemberPaidSubscriptionEvent = MemberPaidSubscriptionEvent;
|
this._MemberPaidSubscriptionEvent = MemberPaidSubscriptionEvent;
|
||||||
this._MemberPaymentEvent = MemberPaymentEvent;
|
this._MemberPaymentEvent = MemberPaymentEvent;
|
||||||
@ -65,7 +67,8 @@ module.exports = class EventRepository {
|
|||||||
{type: 'click_event', action: 'getClickEvents'},
|
{type: 'click_event', action: 'getClickEvents'},
|
||||||
{type: 'aggregated_click_event', action: 'getAggregatedClickEvents'},
|
{type: 'aggregated_click_event', action: 'getAggregatedClickEvents'},
|
||||||
{type: 'signup_event', action: 'getSignupEvents'},
|
{type: 'signup_event', action: 'getSignupEvents'},
|
||||||
{type: 'subscription_event', action: 'getSubscriptionEvents'}
|
{type: 'subscription_event', action: 'getSubscriptionEvents'},
|
||||||
|
{type: 'donation_event', action: 'getDonationEvents'}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Some events are not filterable by post_id
|
// Some events are not filterable by post_id
|
||||||
@ -352,6 +355,59 @@ module.exports = class EventRepository {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getDonationEvents(options = {}, filter) {
|
||||||
|
options = {
|
||||||
|
...options,
|
||||||
|
withRelated: [
|
||||||
|
'member',
|
||||||
|
'postAttribution',
|
||||||
|
'userAttribution',
|
||||||
|
'tagAttribution'
|
||||||
|
],
|
||||||
|
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'
|
||||||
|
}),
|
||||||
|
|
||||||
|
(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'}
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const {data: models, meta} = await this._DonationPaymentEvent.findPage(options);
|
||||||
|
|
||||||
|
const data = models.map((model) => {
|
||||||
|
const json = model.toJSON(options);
|
||||||
|
delete json.postAttribution?.mobiledoc;
|
||||||
|
delete json.postAttribution?.lexical;
|
||||||
|
delete json.postAttribution?.plaintext;
|
||||||
|
return {
|
||||||
|
type: 'donation_event',
|
||||||
|
data: {
|
||||||
|
...json,
|
||||||
|
attribution: this._memberAttributionService.getEventAttribution(model)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
meta
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async getCommentEvents(options = {}, filter) {
|
async getCommentEvents(options = {}, filter) {
|
||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
|
Loading…
Reference in New Issue
Block a user