f8966e26c8
no issue
- "Recommendations" feature was released in Ghost
[v5.71.0](https://github.com/TryGhost/Ghost/releases/tag/v5.71.0)
(commit: 1b82efe5d2
)
- [Project
details](https://www.notion.so/ghost/Recommentions-5be89ec0d02a4c9b9310a964f9b22901?pvs=4)
166 lines
5.2 KiB
JavaScript
166 lines
5.2 KiB
JavaScript
import $ from 'jquery';
|
|
import Ember from 'ember';
|
|
import EmberError from '@ember/error';
|
|
import Service, {inject as service} from '@ember/service';
|
|
import classic from 'ember-classic-decorator';
|
|
import {computed, set} from '@ember/object';
|
|
import {inject} from 'ghost-admin/decorators/inject';
|
|
|
|
export function feature(name, options = {}) {
|
|
let {user, onChange} = options;
|
|
let watchedProps = user ? [`accessibility.${name}`] : [`config.${name}`, `labs.${name}`];
|
|
|
|
return computed.apply(Ember, watchedProps.concat({
|
|
get() {
|
|
let enabled = false;
|
|
|
|
if (user) {
|
|
enabled = this.get(`accessibility.${name}`);
|
|
} else if (typeof this.get(`config.${name}`) === 'boolean') {
|
|
enabled = this.get(`config.${name}`);
|
|
} else {
|
|
enabled = this.get(`labs.${name}`) || false;
|
|
}
|
|
|
|
return enabled;
|
|
},
|
|
set(key, value) {
|
|
this.update(key, value, options);
|
|
|
|
if (onChange) {
|
|
// value must be passed here because the value isn't set until
|
|
// the setter function returns
|
|
this.get(onChange).bind(this)(value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}));
|
|
}
|
|
|
|
@classic
|
|
export default class FeatureService extends Service {
|
|
@service lazyLoader;
|
|
@service notifications;
|
|
@service session;
|
|
@service settings;
|
|
@service store;
|
|
|
|
@inject config;
|
|
|
|
// features
|
|
@feature('emailAnalytics') emailAnalytics;
|
|
|
|
// user-specific flags
|
|
@feature('nightShift', {user: true, onChange: '_setAdminTheme'})
|
|
nightShift;
|
|
|
|
// user-specific referral invitation
|
|
@feature('referralInviteDismissed', {user: true}) referralInviteDismissed;
|
|
|
|
// labs flags
|
|
@feature('urlCache') urlCache;
|
|
@feature('lexicalMultiplayer') lexicalMultiplayer;
|
|
@feature('audienceFeedback') audienceFeedback;
|
|
@feature('webmentions') webmentions;
|
|
@feature('stripeAutomaticTax') stripeAutomaticTax;
|
|
@feature('emailCustomization') emailCustomization;
|
|
@feature('i18n') i18n;
|
|
@feature('announcementBar') announcementBar;
|
|
@feature('signupCard') signupCard;
|
|
@feature('collections') collections;
|
|
@feature('mailEvents') mailEvents;
|
|
@feature('collectionsCard') collectionsCard;
|
|
@feature('importMemberTier') importMemberTier;
|
|
@feature('tipsAndDonations') tipsAndDonations;
|
|
@feature('lexicalIndicators') lexicalIndicators;
|
|
@feature('adminXDemo') adminXDemo;
|
|
@feature('ActivityPub') ActivityPub;
|
|
@feature('internalLinking') internalLinking;
|
|
@feature('editorExcerpt') editorExcerpt;
|
|
@feature('contentVisibility') contentVisibility;
|
|
|
|
_user = null;
|
|
|
|
@computed('settings.labs')
|
|
get labs() {
|
|
let labs = this.settings.labs;
|
|
|
|
try {
|
|
return JSON.parse(labs) || {};
|
|
} catch (e) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
@computed('_user.accessibility')
|
|
get accessibility() {
|
|
let accessibility = this.get('_user.accessibility');
|
|
|
|
try {
|
|
return JSON.parse(accessibility) || {};
|
|
} catch (e) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
fetch() {
|
|
return this.settings.fetch().then(() => {
|
|
this.set('_user', this.session.user);
|
|
return this._setAdminTheme().then(() => true);
|
|
});
|
|
}
|
|
|
|
update(key, value, options = {}) {
|
|
let serviceProperty = options.user ? 'accessibility' : 'labs';
|
|
let model = this.get(options.user ? '_user' : 'settings');
|
|
let featureObject = this.get(serviceProperty);
|
|
|
|
// set the new key value for either the labs property or the accessibility property
|
|
set(featureObject, key, value);
|
|
|
|
if (options.requires && value === true) {
|
|
options.requires.forEach((flag) => {
|
|
set(featureObject, flag, true);
|
|
});
|
|
}
|
|
|
|
// update the 'labs' or 'accessibility' key of the model
|
|
model.set(serviceProperty, JSON.stringify(featureObject));
|
|
|
|
return model.save().then(() => {
|
|
// return the labs key value that we get from the server
|
|
this.notifyPropertyChange(serviceProperty);
|
|
return this.get(`${serviceProperty}.${key}`);
|
|
}).catch((error) => {
|
|
model.rollbackAttributes();
|
|
this.notifyPropertyChange(serviceProperty);
|
|
|
|
// we'll always have an errors object unless we hit a
|
|
// validation error
|
|
if (!error) {
|
|
throw new EmberError(`Validation of the feature service ${options.user ? 'user' : 'settings'} model failed when updating ${serviceProperty}.`);
|
|
}
|
|
|
|
this.notifications.showAPIError(error);
|
|
|
|
return this.get(`${serviceProperty}.${key}`);
|
|
});
|
|
}
|
|
|
|
_setAdminTheme(enabled) {
|
|
let nightShift = enabled;
|
|
|
|
if (typeof nightShift === 'undefined') {
|
|
nightShift = enabled || this.nightShift;
|
|
}
|
|
|
|
return this.lazyLoader.loadStyle('dark', 'assets/ghost-dark.css', true).then(() => {
|
|
$('link[title=dark]').prop('disabled', !nightShift);
|
|
}).catch(() => {
|
|
//TODO: Also disable toggle from settings and Labs hover
|
|
$('link[title=dark]').prop('disabled', true);
|
|
});
|
|
}
|
|
}
|