mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-21 18:01:36 +03:00
7b443d4b63
no issue The `config` service has been a source of confusion when writing with modern Ember patterns because it's use of the deprecated `ProxyMixin` forced all property access/setting to go via `.get()` and `.set()` whereas the rest of the system has mostly (there are a few other uses of ProxyObjects remaining) eliminated the use of the non-native get/set methods. - removed use of `ProxyMixin` in the `config` service by grabbing the API response after fetching and using `Object.defineProperty()` to add native getters/setters that pass through to a tracked object holding the API response data. Ember's autotracking automatically works across the native getters/setters so we can then use the service as if it was any other native object - updated all code to use `config.{attrName}` directly for getting/setting instead of `.get()` and `.set()` - removed unnecessary async around `config.availableTimezones` which wasn't making any async calls
106 lines
3.0 KiB
JavaScript
106 lines
3.0 KiB
JavaScript
import LimitService from '@tryghost/limit-service';
|
|
import RSVP from 'rsvp';
|
|
import Service, {inject as service} from '@ember/service';
|
|
import {bind} from '@ember/runloop';
|
|
|
|
class LimitError {
|
|
constructor({errorType, errorDetails, message}) {
|
|
this.errorType = errorType;
|
|
this.errorDetails = errorDetails;
|
|
this.message = message;
|
|
}
|
|
}
|
|
|
|
class IncorrectUsageError extends LimitError {
|
|
constructor(options) {
|
|
super(Object.assign({errorType: 'IncorrectUsageError'}, options));
|
|
}
|
|
}
|
|
|
|
class HostLimitError extends LimitError {
|
|
constructor(options) {
|
|
super(Object.assign({errorType: 'HostLimitError'}, options));
|
|
}
|
|
}
|
|
|
|
export default class LimitsService extends Service {
|
|
@service config;
|
|
@service store;
|
|
@service membersStats;
|
|
|
|
constructor() {
|
|
super(...arguments);
|
|
|
|
let limits = this.config.hostSettings?.limits;
|
|
|
|
this.limiter = new LimitService();
|
|
|
|
if (!limits) {
|
|
return;
|
|
}
|
|
|
|
let helpLink;
|
|
|
|
if (this.config.hostSettings?.billing?.enabled === true
|
|
&& this.config.hostSettings?.billing?.url
|
|
) {
|
|
helpLink = this.config.hostSettings.billing?.url;
|
|
} else {
|
|
helpLink = 'https://ghost.org/help/';
|
|
}
|
|
|
|
this.limiter.loadLimits({
|
|
limits: this.decorateWithCountQueries(limits),
|
|
helpLink,
|
|
errors: {
|
|
HostLimitError,
|
|
IncorrectUsageError
|
|
}
|
|
});
|
|
}
|
|
|
|
async checkWouldGoOverLimit(limitName, metadata = {}) {
|
|
return this.limiter.checkWouldGoOverLimit(limitName, metadata);
|
|
}
|
|
|
|
decorateWithCountQueries(limits) {
|
|
if (limits.staff) {
|
|
limits.staff.currentCountQuery = bind(this, this.getStaffUsersCount);
|
|
}
|
|
|
|
if (limits.members) {
|
|
limits.members.currentCountQuery = bind(this, this.getMembersCount);
|
|
}
|
|
|
|
if (limits.newsletters) {
|
|
limits.newsletters.currentCountQuery = bind(this, this.getNewslettersCount);
|
|
}
|
|
|
|
return limits;
|
|
}
|
|
|
|
async getStaffUsersCount() {
|
|
return RSVP.hash({
|
|
users: this.store.findAll('user', {reload: true}),
|
|
invites: this.store.findAll('invite', {reload: true}),
|
|
roles: this.store.findAll('role', {reload: true}) // NOTE: roles have to be fetched as they are not always loaded with invites
|
|
}).then((data) => {
|
|
const staffUsers = data.users.filter(u => u.get('status') !== 'inactive' && u.role.get('name') !== 'Contributor');
|
|
const staffInvites = data.invites.filter(i => i.role.get('name') !== 'Contributor');
|
|
|
|
return staffUsers.length + staffInvites.length;
|
|
});
|
|
}
|
|
|
|
async getMembersCount() {
|
|
const counts = await this.membersStats.fetchCounts();
|
|
|
|
return counts.total;
|
|
}
|
|
|
|
async getNewslettersCount() {
|
|
const activeNewsletters = await this.store.query('newsletter', {filter: 'status:active', limit: 'all'});
|
|
return activeNewsletters.length;
|
|
}
|
|
}
|