mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-02 08:13:34 +03:00
bd60c8089b
closes https://github.com/TryGhost/Team/issues/776 Since switching to using a real NQL filter in the `posts.email_recipient_filter` field where we used to show `free members`, `paid members`, or `all members` we were showing `status:free`, `status:-free`, and `status:free,status:-free` respectively. If labels are used in a filter the text became even longer. - added a `membersCountCache` service - `.count(filter)` fetches a numeric count from the members API, if the filter has been counted in the last minute it returns the count directly from a cache instead to avoid hammering the members API when we show counts in multiple places across the UI - `.countString(filter)` fetches a count but returns a humanized string with the logic extracted from what we displayed in the confirm email sending modal - added a `<GhRecipientFilterCount @filter="" />` component that acts as a wrapper around the async count from `membersCountCache` - updated confirm email send modal, plus save notification and editor status displays for scheduled posts to use the new service and component
80 lines
2.4 KiB
JavaScript
80 lines
2.4 KiB
JavaScript
import Service from '@ember/service';
|
|
import moment from 'moment';
|
|
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
|
|
import {inject as service} from '@ember/service';
|
|
import {task} from 'ember-concurrency-decorators';
|
|
|
|
export default class MembersCountCacheService extends Service {
|
|
@service session;
|
|
@service store;
|
|
|
|
cache = {};
|
|
|
|
async count(filter) {
|
|
const cachedValue = this.cache[filter];
|
|
|
|
if (cachedValue && moment().diff(cachedValue.time, 'seconds') > 60) {
|
|
return cachedValue.count;
|
|
}
|
|
|
|
const count = this._countMembersTask.perform(filter);
|
|
|
|
this.cache[filter] = {count, time: moment()};
|
|
|
|
return count;
|
|
}
|
|
|
|
async countString(filter, {knownCount} = {}) {
|
|
const user = await this.session.user;
|
|
|
|
const basicFilter = filter.replace(/^subscribed:true\+\((.*)\)$/, '$1');
|
|
const filterParts = basicFilter.split(',');
|
|
const isFree = filterParts.length === 1 && filterParts[0] === 'status:free';
|
|
const isPaid = filterParts.length === 1 && filterParts[0] === 'status:-free';
|
|
const isAll = filterParts.includes('status:free') && filterParts.includes('status:-free');
|
|
|
|
// editors don't have permission to browse members so can't retrieve a count
|
|
// TODO: remove when editors have relevant permissions or we have a different way of fetching counts
|
|
if (user.isEditor && knownCount === undefined) {
|
|
if (isFree) {
|
|
return 'all free members';
|
|
}
|
|
if (isPaid) {
|
|
return 'all paid members';
|
|
}
|
|
if (isAll) {
|
|
return 'all members';
|
|
}
|
|
|
|
return 'a custom members segment';
|
|
}
|
|
|
|
const recipientCount = knownCount !== undefined ? knownCount : await this.count(filter);
|
|
|
|
if (isFree) {
|
|
return ghPluralize(recipientCount, 'free member');
|
|
}
|
|
|
|
if (isPaid) {
|
|
return ghPluralize(recipientCount, 'paid member');
|
|
}
|
|
|
|
return ghPluralize(recipientCount, 'member');
|
|
}
|
|
|
|
@task
|
|
*_countMembersTask(filter) {
|
|
if (!filter) {
|
|
return 0;
|
|
}
|
|
|
|
try {
|
|
const result = yield this.store.query('member', {filter, limit: 1, page: 1});
|
|
return result.meta.pagination.total;
|
|
} catch (e) {
|
|
console.error(e); // eslint-disable-line
|
|
return 0;
|
|
}
|
|
}
|
|
}
|