Updated members count to use selected newsletter when publishing

refs https://github.com/TryGhost/Team/issues/1576

- Passes the selected newsletter to the recipient selector
- Added a `recipientFilter` getter to the newsletter model to make changes easier in the future
- Updates the `fullRecipientFilter` in the new publishing flow to use the newsletter's recipientFilter
- Already takes future paid only newsletters into account
- The counts in the status message after publishing is not updated yet (requires https://github.com/TryGhost/Team/issues/1569)
- The counts in the scheduled notification is not updated yet (requires https://github.com/TryGhost/Team/issues/1569)
This commit is contained in:
Simon Backx 2022-05-05 14:33:26 +02:00
parent 03ba0da1a7
commit 1f5f9645e6
11 changed files with 44 additions and 24 deletions

View File

@ -162,7 +162,7 @@ export class PublishOptions {
}
get fullRecipientFilter() {
let filter = `newsletters:${this.newsletter.slug}`;
let filter = this.newsletter.recipientFilter;
if (this.recipientFilter) {
filter += `+(${this.recipientFilter})`;

View File

@ -24,6 +24,7 @@
<GhMembersRecipientSelect
@filter={{@publishOptions.recipientFilter}}
@newsletter={{@publishOptions.newsletter}}
@onChange={{@publishOptions.setRecipientFilter}}
@renderInPlace={{false}}
@dropdownClass="gh-publishmenu-newsletter-dropdown"

View File

@ -1,4 +1,4 @@
<div class="gh-publishmenu-send-to-option">
<div class="gh-publishmenu-send-to-option" {{did-update this.onUpdateNewsletter @newsletter }}>
<p>Free members <span class="gh-publishmenu-emailcount" data-test-email-count="free-members">{{this.freeMemberCountLabel}}</span></p>
<div class="for-switch x-small {{if @disabled "disabled"}}">
<label class="switch" for="send-email-to-free">

View File

@ -78,6 +78,11 @@ export default class GhMembersRecipientSelect extends Component {
return '';
}
@action
onUpdateNewsletter() {
this.fetchMemberCountsTask.perform();
}
@action
toggleFilter(filter) {
if (this.args.disabled) {
@ -202,15 +207,15 @@ export default class GhMembersRecipientSelect extends Component {
*fetchMemberCountsTask() {
const user = yield this.session.user;
if (!user.isAdmin) {
if (!user.isAdmin || !this.args.newsletter) {
return;
}
yield Promise.all([
this.store.query('member', {filter: 'newsletters.status:active+status:free', limit: 1}).then((res) => {
this.store.query('member', {filter: this.args.newsletter.recipientFilter + '+status:free', limit: 1}).then((res) => {
this.freeMemberCount = res.meta.pagination.total;
}),
this.store.query('member', {filter: 'newsletters.status:active+status:-free', limit: 1}).then((res) => {
this.store.query('member', {filter: this.args.newsletter.recipientFilter + '+status:-free', limit: 1}).then((res) => {
this.paidMemberCount = res.meta.pagination.total;
})
]);

View File

@ -80,6 +80,7 @@
<GhMembersRecipientSelect
@filter={{@recipientsFilter}}
@newsletter={{@selectedNewsletter}}
@onChange={{@setSendEmailWhenPublished}}
/>
</div>

View File

@ -59,6 +59,7 @@
<div class="form-group">
<GhMembersRecipientSelect
@filter={{@recipientsFilter}}
@newsletter={{this.selectedNewsletter}}
@disabled={{true}}
/>
</div>

View File

@ -401,7 +401,7 @@ export default Component.extend({
post: this.post,
emailOnly: this.emailOnly,
sendEmailWhenPublished: this.sendEmailWhenPublished,
newsletterId: this.newsletterId,
newsletter: this.selectedNewsletter,
isScheduled: saveType === 'schedule',
confirm: this.saveWithConfirmedPublish.perform,
retryEmailSend: this.retryEmailSendTask.perform
@ -449,7 +449,6 @@ export default Component.extend({
}),
fetchNewslettersTask: task(function* () {
if (this.feature.multipleNewsletters) {
const newsletters = yield this.store.query('newsletter', {
filter: 'status:active',
order: 'sort_order ASC'
@ -459,7 +458,6 @@ export default Component.extend({
this.defaultNewsletter = defaultNewsletter;
this.set('selectedNewsletter', defaultNewsletter);
}
}),
_saveTask: task(function* () {

View File

@ -59,8 +59,8 @@ export default class ConfirmPublishModal extends Component {
@task
*countRecipientsTask() {
const {sendEmailWhenPublished} = this.args.data;
const filter = `newsletters.status:active+(${sendEmailWhenPublished})`;
const {sendEmailWhenPublished,newsletter} = this.args.data;
const filter = `${newsletter.recipientFilter}+(${sendEmailWhenPublished})`;
this.memberCount = sendEmailWhenPublished ? (yield this.membersCountCache.count(filter)) : 0;
this.memberCountString = sendEmailWhenPublished ? (yield this.membersCountCache.countString(filter)) : '0 members';

View File

@ -1079,6 +1079,7 @@ export default class EditorController extends Controller {
let description = emailOnly ? ['Will be sent'] : ['Will be published'];
if (emailRecipientFilter && emailRecipientFilter !== 'none') {
// TODO: replace active filter with newsletter.recipientFilter (requires https://github.com/TryGhost/Team/issues/1569)
const recipientCount = await this.membersCountCache.countString(`newsletters.status:active+(${emailRecipientFilter})`);
description.push(`${!emailOnly ? 'and delivered ' : ''}to <span><strong>${recipientCount}</strong></span>`);
}

View File

@ -13,7 +13,6 @@ export default class Newsletter extends Model.extend(ValidationEngine) {
@attr({defaultValue: 'newsletter'}) senderReplyTo;
@attr({defaultValue: 'active'}) status;
@attr({defaultValue: ''}) recipientFilter;
@attr({defaultValue: true}) subscribeOnSignup;
@attr({defaultValue: 'members'}) visibility;
@attr({defaultValue: 0}) sortOrder;
@ -34,4 +33,15 @@ export default class Newsletter extends Model.extend(ValidationEngine) {
// HACK - not a real model attribute but a workaround for Ember Data not
// exposing meta from save responses
@attr _meta;
/**
* The filter that we should use to filter out members that are subscribed to this newsletter
*/
get recipientFilter() {
const idFilter = 'newsletters.id:' + this.id;
if (this.visibility === 'paid') {
return idFilter + '+status:-free';
}
return idFilter;
}
}

View File

@ -6,6 +6,7 @@ import {authenticateSession, invalidateSession} from 'ember-simple-auth/test-sup
import {beforeEach, describe, it} from 'mocha';
import {blur, click, currentRouteName, currentURL, fillIn, find, findAll, triggerEvent} from '@ember/test-helpers';
import {datepickerSelect} from 'ember-power-datepicker/test-support';
import {enableLabsFlag} from '../helpers/labs-flag';
import {enableMailgun} from '../helpers/mailgun';
import {enableNewsletters} from '../helpers/newsletters';
import {enableStripe} from '../helpers/stripe';
@ -845,6 +846,7 @@ describe('Acceptance: Editor', function () {
const role = this.server.create('role', {name: 'Administrator'});
user = this.server.create('user', {roles: [role]});
this.server.loadFixtures('settings');
enableLabsFlag(this.server, 'multipleNewsletters');
return await authenticateSession();
});
@ -876,7 +878,8 @@ describe('Acceptance: Editor', function () {
// Enable stripe to also show paid members breakdown
enableStripe(this.server);
const newsletter = this.server.create('newsletter', {status: 'active'});
// Note: we need to set the ID of a newsletter to some string value because of how NQL filters work.
const newsletter = this.server.create('newsletter', {status: 'active', name: 'test newsletter', id: 'test-newsletter'});
this.server.createList('member', 4, {status: 'free', newsletters: [newsletter]});
this.server.createList('member', 2, {status: 'paid', newsletters: [newsletter]});