Removed need for .get() with settings service

no issue

The `settings` 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 `settings` service by grabbing the attributes off the setting model after fetching and using `Object.defineProperty()` to add native getters/setters that pass through to the model's getters/setters. 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 `settings.{attrName}` directly for getting/setting instead of `.get()` and `.set()`
- removed use of observer in the `customViews` service because it was being set up before the native properties had been added on the settings service meaning autotracking wasn't able to set up properly
This commit is contained in:
Kevin Ansfield 2022-10-07 14:23:21 +01:00
parent b5fd02c9e8
commit 060d791a63
72 changed files with 368 additions and 374 deletions

View File

@ -39,7 +39,7 @@ export default class ModalPostPreviewEmailComponent extends Component {
get mailgunIsEnabled() {
return this.config.get('mailgunIsConfigured') ||
!!(this.settings.get('mailgunApiKey') && this.settings.get('mailgunDomain') && this.settings.get('mailgunBaseUrl'));
!!(this.settings.mailgunApiKey && this.settings.mailgunDomain && this.settings.mailgunBaseUrl);
}
@action

View File

@ -24,7 +24,7 @@ export default class ModalPostPreviewSocialComponent extends Component {
get _fallbackDescription() {
return this.args.post.customExcerpt ||
this.serpDescription ||
this.settings.get('description');
this.settings.description;
}
@action
@ -107,7 +107,7 @@ export default class ModalPostPreviewSocialComponent extends Component {
}
get facebookImage() {
return this.args.post.ogImage || this.args.post.featureImage || this.settings.get('ogImage') || this.settings.get('coverImage');
return this.args.post.ogImage || this.args.post.featureImage || this.settings.ogImage || this.settings.coverImage;
}
@action
@ -166,7 +166,7 @@ export default class ModalPostPreviewSocialComponent extends Component {
}
get twitterImage() {
return this.args.post.twitterImage || this.args.post.featureImage || this.settings.get('twitterImage') || this.settings.get('coverImage');
return this.args.post.twitterImage || this.args.post.featureImage || this.settings.twitterImage || this.settings.coverImage;
}
@action

View File

@ -66,7 +66,7 @@ export default class PublishFlowOptions extends Component {
}
if (this.args.publishOptions.isScheduled) {
const scheduleMoment = moment.tz(this.args.publishOptions.scheduledAtUTC, this.settings.get('timezone'));
const scheduleMoment = moment.tz(this.args.publishOptions.scheduledAtUTC, this.settings.timezone);
buttonText += `, on ${scheduleMoment.format('MMMM Do')}`;
} else {
buttonText += ', right now';

View File

@ -9,7 +9,7 @@ export default class PublishAtOption extends Component {
@action
setDate(selectedDate) {
// selectedDate is a Date object that contains the correct date string in the blog timezone
const selectedMoment = moment.tz(selectedDate, this.settings.get('timezone'));
const selectedMoment = moment.tz(selectedDate, this.settings.timezone);
const {years, months, date} = selectedMoment.toObject();
// Create a new moment from existing scheduledAtUTC _in site timezone_.
@ -17,7 +17,7 @@ export default class PublishAtOption extends Component {
// to account for the converted UTC date being yesterday/tomorrow.
const newDate = moment.tz(
this.args.publishOptions.scheduledAtUTC,
this.settings.get('timezone')
this.settings.timezone
);
newDate.set({years, months, date});
@ -27,7 +27,7 @@ export default class PublishAtOption extends Component {
@action
setTime(time, event) {
const newDate = moment.tz(this.args.publishOptions.scheduledAtUTC, this.settings.get('timezone'));
const newDate = moment.tz(this.args.publishOptions.scheduledAtUTC, this.settings.timezone);
// used to reset the time value on blur if it's invalid
const oldTime = newDate.format('HH:mm');

View File

@ -32,7 +32,7 @@ export default class GhEditorPostStatusComponent extends Component {
return formatPostTime(
this.args.post.publishedAtUTC,
{timezone: this.settings.get('timezone'), scheduled: true}
{timezone: this.settings.timezone, scheduled: true}
);
}

View File

@ -1,14 +1,11 @@
import Component from '@glimmer/component';
import validator from 'validator';
import {action} from '@ember/object';
import {get, set} from '@ember/object';
export default class GhFacebookUrlInput extends Component {
// NOTE: `get` and `set` are required when reading/writing model properties
// because we can be dealing with proxy objects such as the settings service
get value() {
const {model, modelProperty, scratchValue} = this.args;
return scratchValue || get(model, modelProperty);
return scratchValue || model[modelProperty];
}
@action
@ -28,7 +25,7 @@ export default class GhFacebookUrlInput extends Component {
if (!newUrl) {
// Clear out the Facebook url
set(model, modelProperty, null);
model[modelProperty] = null;
this.args.setScratchValue?.(null);
return;
}
@ -51,7 +48,7 @@ export default class GhFacebookUrlInput extends Component {
throw 'invalid url';
}
set(model, modelProperty, newUrl);
model[modelProperty] = newUrl;
this.args.setScratchValue?.(null);
} catch (e) {
if (e === 'invalid url') {

View File

@ -21,7 +21,7 @@ export default class GhKoenigEditorReactComponent extends Component {
}
get accentColor() {
const color = this.settings.get('accentColor');
const color = this.settings.accentColor;
if (color && color[0] === '#') {
return color.slice(1);
}

View File

@ -164,7 +164,7 @@ export default class GhMarkdownEditor extends Component.extend(ShortcutsMixin) {
toolbar.splice(index, 1);
}
if (this.get('settings.unsplash')) {
if (this.settings.unsplash) {
let image = toolbar.findBy('name', 'image');
let index = toolbar.indexOf(image) + 1;

View File

@ -42,7 +42,7 @@ export default class Email extends Component {
'config.mailgunIsConfigured'
)
get mailgunIsEnabled() {
return this.get('settings.mailgunApiKey') && this.get('settings.mailgunDomain') && this.get('settings.mailgunBaseUrl') || this.get('config.mailgunIsConfigured');
return this.settings.mailgunApiKey && this.settings.mailgunDomain && this.settings.mailgunBaseUrl || this.get('config.mailgunIsConfigured');
}
@action

View File

@ -12,13 +12,13 @@ const VISIBILITIES = [
@classic
export default class GhPsmVisibilityInput extends Component {
@service settings;
// public attrs
post = null;
@computed('post.visibility')
get selectedVisibility() {
return this.get('post.visibility') || this.settings.get('defaultContentVisibility');
return this.get('post.visibility') || this.settings.defaultContentVisibility;
}
init() {

View File

@ -1,13 +1,10 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {get, set} from '@ember/object';
export default class GhTwitterUrlInput extends Component {
// NOTE: `get` and `set` are required when reading/writing model properties
// because we can be dealing with proxy objects such as the settings service
get value() {
const {model, modelProperty, scratchValue} = this.args;
return scratchValue || get(model, modelProperty);
return scratchValue || model[modelProperty];
}
@action
@ -27,7 +24,7 @@ export default class GhTwitterUrlInput extends Component {
if (!newUrl) {
// Clear out the Twitter url
set(model, modelProperty, '');
model[modelProperty] = '';
this.args.setScratchValue?.(null);
return;
}
@ -52,7 +49,7 @@ export default class GhTwitterUrlInput extends Component {
return;
}
set(model, modelProperty, `https://twitter.com/${username}`);
model[modelProperty] = `https://twitter.com/${username}`;
this.args.setScratchValue?.(null);
model.hasValidated.pushObject(modelProperty);

View File

@ -19,7 +19,7 @@ export default class MembersActivityEventTypeFilter extends Component {
get availableEventTypes() {
const extended = [...ALL_EVENT_TYPES];
if (this.settings.get('commentsEnabled') !== 'off') {
if (this.settings.commentsEnabled !== 'off') {
extended.push({event: 'comment_event', icon: 'event-comment', name: 'Comments'});
}

View File

@ -178,12 +178,12 @@ export default class MembersFilter extends Component {
});
// exclude subscription filters if Stripe isn't connected
if (!this.settings.get('paidMembersEnabled')) {
if (!this.settings.paidMembersEnabled) {
availableFilters = availableFilters.reject(prop => prop.group === 'Subscription');
}
// exclude email filters if email functionality is disabled
if (this.settings.get('editorDefaultEmailRecipients') === 'disabled') {
if (this.settings.editorDefaultEmailRecipients === 'disabled') {
availableFilters = availableFilters.reject(prop => prop.group === 'Email');
}
@ -253,7 +253,7 @@ export default class MembersFilter extends Component {
} else if (filterProperty.valueType === 'date') {
let filterValue;
let tzMoment = moment.tz(moment(filter.value).format('YYYY-MM-DD'), this.settings.get('timezone'));
let tzMoment = moment.tz(moment(filter.value).format('YYYY-MM-DD'), this.settings.timezone);
if (relationStr === '>') {
tzMoment = tzMoment.set({hour: 23, minute: 59, second: 59});
@ -364,7 +364,7 @@ export default class MembersFilter extends Component {
relation,
relationOptions: FILTER_RELATIONS_OPTIONS[key],
value,
timezone: this.settings.get('timezone')
timezone: this.settings.timezone
});
}
}
@ -429,7 +429,7 @@ export default class MembersFilter extends Component {
@action
handleSubmitKeyup(e) {
e.preventDefault();
if (e.key === 'Enter') {
this.applyFilter();
}
@ -465,7 +465,7 @@ export default class MembersFilter extends Component {
}
if (newProp.valueType === 'date' && !defaultValue) {
defaultValue = moment(moment.tz(this.settings.get('timezone')).format('YYYY-MM-DD')).toDate();
defaultValue = moment(moment.tz(this.settings.timezone).format('YYYY-MM-DD')).toDate();
}
let defaultRelation = this.availableFilterRelationsOptions[newType][0].name;
@ -479,7 +479,7 @@ export default class MembersFilter extends Component {
relation: defaultRelation,
relationOptions: this.availableFilterRelationsOptions[newType],
value: defaultValue,
timezone: this.settings.get('timezone')
timezone: this.settings.timezone
});
const filterToSwap = this.filters.find(f => f === filter);

View File

@ -14,22 +14,22 @@ export default class ModalEmailDesignSettings extends ModalComponent {
@service session;
@service settings;
@tracked headerImage = this.settings.get('newsletterHeaderImage');
@tracked showHeaderIcon = this.settings.get('newsletterShowHeaderIcon');
@tracked showHeaderTitle = this.settings.get('newsletterShowHeaderTitle');
@tracked titleFontCategory = this.settings.get('newsletterTitleFontCategory');
@tracked titleAlignment = this.settings.get('newsletterTitleAlignment');
@tracked showFeatureImage = this.settings.get('newsletterShowFeatureImage');
@tracked bodyFontCategory = this.settings.get('newsletterBodyFontCategory');
@tracked footerContent = this.settings.get('newsletterFooterContent');
@tracked showBadge = this.settings.get('newsletterShowBadge');
@tracked headerImage = this.settings.newsletterHeaderImage;
@tracked showHeaderIcon = this.settings.newsletterShowHeaderIcon;
@tracked showHeaderTitle = this.settings.newsletterShowHeaderTitle;
@tracked titleFontCategory = this.settings.newsletterTitleFontCategory;
@tracked titleAlignment = this.settings.newsletterTitleAlignment;
@tracked showFeatureImage = this.settings.newsletterShowFeatureImage;
@tracked bodyFontCategory = this.settings.newsletterBodyFontCategory;
@tracked footerContent = this.settings.newsletterFooterContent;
@tracked showBadge = this.settings.newsletterShowBadge;
currentDate = moment().format('D MMM YYYY');
copyrightYear = new Date().getFullYear();
imageExtensions = IMAGE_EXTENSIONS;
get showHeader() {
return (this.showHeaderIcon && this.settings.get('icon')) || this.showHeaderTitle;
return (this.showHeaderIcon && this.settings.icon) || this.showHeaderTitle;
}
get featureImageUrl() {
@ -77,15 +77,15 @@ export default class ModalEmailDesignSettings extends ModalComponent {
@task({drop: true})
*saveSettings() {
this.settings.set('newsletterHeaderImage', this.headerImage);
this.settings.set('newsletterShowHeaderIcon', this.showHeaderIcon);
this.settings.set('newsletterShowHeaderTitle', this.showHeaderTitle);
this.settings.set('newsletterTitleFontCategory', this.titleFontCategory);
this.settings.set('newsletterTitleAlignment', this.titleAlignment);
this.settings.set('newsletterShowFeatureImage', this.showFeatureImage);
this.settings.set('newsletterBodyFontCategory', this.bodyFontCategory);
this.settings.set('newsletterFooterContent', this.footerContent);
this.settings.set('newsletterShowBadge', this.showBadge);
this.settings.newsletterHeaderImage = this.headerImage;
this.settings.newsletterShowHeaderIcon = this.showHeaderIcon;
this.settings.newsletterShowHeaderTitle = this.showHeaderTitle;
this.settings.newsletterTitleFontCategory = this.titleFontCategory;
this.settings.newsletterTitleAlignment = this.titleAlignment;
this.settings.newsletterShowFeatureImage = this.showFeatureImage;
this.settings.newsletterBodyFontCategory = this.bodyFontCategory;
this.settings.newsletterFooterContent = this.footerContent;
this.settings.newsletterShowBadge = this.showBadge;
yield this.settings.save();
this.closeModal();

View File

@ -30,10 +30,10 @@ export default class ModalFreeMembershipSettings extends ModalBase {
this.close();
},
updateName(value) {
this.settings.set('membersFreePriceName', value);
this.settings.membersFreePriceName = value;
},
updateDescription(value) {
this.settings.set('membersFreePriceDescription', value);
this.settings.membersFreePriceDescription = value;
},
setFreeSignupRedirect(url) {
this.freeSignupRedirect = url;
@ -47,7 +47,7 @@ export default class ModalFreeMembershipSettings extends ModalBase {
*save() {
try {
this.send('validateFreeSignupRedirect');
if (this.settings.get('errors').length !== 0) {
if (this.settings.errors.length !== 0) {
return;
}
yield this.settings.save();
@ -61,12 +61,12 @@ export default class ModalFreeMembershipSettings extends ModalBase {
_validateSignupRedirect(url, type) {
let errMessage = `Please enter a valid URL`;
this.settings.get('errors').remove(type);
this.settings.get('hasValidated').removeObject(type);
this.settings.errors.remove(type);
this.settings.hasValidated.removeObject(type);
if (url === null) {
this.settings.get('errors').add(type, errMessage);
this.settings.get('hasValidated').pushObject(type);
this.settings.errors.add(type, errMessage);
this.settings.hasValidated.pushObject(type);
return false;
}
@ -77,9 +77,9 @@ export default class ModalFreeMembershipSettings extends ModalBase {
if (url.href.startsWith(this.siteUrl)) {
const path = url.href.replace(this.siteUrl, '');
this.settings.set(type, path);
this.settings.type = path;
} else {
this.settings.set(type, url.href);
this.settings.type = url.href;
}
}
}

View File

@ -32,7 +32,7 @@ export default ModalComponent.extend({
confirm() {},
backgroundStyle: computed('settings.accentColor', function () {
let color = this.settings.get('accentColor') || '#ffffff';
let color = this.settings.accentColor || '#ffffff';
return htmlSafe(`background-color: ${color}`);
}),
@ -71,20 +71,20 @@ export default ModalComponent.extend({
selectedButtonStyle: computed('settings.portalButtonStyle', function () {
return this.buttonStyleOptions.find((buttonStyle) => {
return (buttonStyle.name === this.settings.get('portalButtonStyle'));
return (buttonStyle.name === this.settings.portalButtonStyle);
});
}),
isFreeChecked: computed('settings.{portalPlans.[],membersSignupAccess}', function () {
const allowedPlans = this.settings.get('portalPlans') || [];
return (this.settings.get('membersSignupAccess') === 'all' && allowedPlans.includes('free'));
const allowedPlans = this.settings.portalPlans || [];
return (this.settings.membersSignupAccess === 'all' && allowedPlans.includes('free'));
}),
isMonthlyChecked: computed('settings.portalPlans.[]', 'membersUtils.paidMembersEnabled', function () {
const allowedPlans = this.settings.get('portalPlans') || [];
const allowedPlans = this.settings.portalPlans || [];
return (this.membersUtils.paidMembersEnabled && allowedPlans.includes('monthly'));
}),
isYearlyChecked: computed('settings.portalPlans.[]', 'membersUtils.paidMembersEnabled', function () {
const allowedPlans = this.settings.get('portalPlans') || [];
const allowedPlans = this.settings.portalPlans || [];
return (this.membersUtils.paidMembersEnabled && allowedPlans.includes('yearly'));
}),
tiers: computed('model.tiers.[]', 'changedTiers.[]', 'isPreloading', function () {
@ -130,13 +130,13 @@ export default ModalComponent.extend({
}];
this.iconExtensions = ICON_EXTENSIONS;
this.changedTiers = [];
this.set('supportAddress', this.parseEmailAddress(this.settings.get('membersSupportAddress')));
this.set('supportAddress', this.parseEmailAddress(this.settings.membersSupportAddress));
this.set('openSection', 'signup-options');
},
didInsertElement() {
this._super(...arguments);
this.settings.get('errors').clear();
this.settings.errors.clear();
},
actions: {
@ -150,11 +150,11 @@ export default ModalComponent.extend({
this.updateAllowedTier(tierId, event.target.checked);
},
togglePortalButton(showButton) {
this.settings.set('portalButton', showButton);
this.settings.portalButton = showButton;
},
togglePortalName(showSignupName) {
this.settings.set('portalName', showSignupName);
this.settings.portalName = showSignupName;
},
toggleSection(section) {
if (this.get('openSection') === section) {
@ -169,7 +169,7 @@ export default ModalComponent.extend({
},
isPlanSelected(plan) {
const allowedPlans = this.settings.get('portalPlans');
const allowedPlans = this.settings.portalPlans;
return allowedPlans.includes(plan);
},
@ -191,11 +191,11 @@ export default ModalComponent.extend({
},
setButtonStyle(buttonStyle) {
this.settings.set('portalButtonStyle', buttonStyle.name);
this.settings.portalButtonStyle = buttonStyle.name;
},
setSignupButtonText(event) {
this.settings.set('portalButtonSignupText', event.target.value);
this.settings.portalButtonSignupText = event.target.value;
},
/**
* Fired after an image upload completes
@ -206,7 +206,7 @@ export default ModalComponent.extend({
imageUploaded(property, results) {
if (results[0]) {
this.set('customIcon', results[0].url);
this.settings.set('portalButtonIcon', results[0].url);
this.settings.portalButtonIcon = results[0].url;
}
},
/**
@ -221,11 +221,11 @@ export default ModalComponent.extend({
deleteCustomIcon() {
this.set('customIcon', null);
this.settings.set('portalButtonIcon', this.membersUtils.defaultIconKeys[0]);
this.settings.portalButtonIcon = this.membersUtils.defaultIconKeys[0];
},
selectDefaultIcon(icon) {
this.settings.set('portalButtonIcon', icon);
this.settings.portalButtonIcon = icon;
},
closeLeaveSettingsModal() {
@ -253,9 +253,9 @@ export default ModalComponent.extend({
this.set('supportAddress', supportAddress);
if (this.config.emailDomain && supportAddress === `noreply@${this.config.emailDomain}`) {
this.settings.set('membersSupportAddress', 'noreply');
this.settings.membersSupportAddress = 'noreply';
} else {
this.settings.set('membersSupportAddress', supportAddress);
this.settings.membersSupportAddress = supportAddress;
}
}
},
@ -270,18 +270,18 @@ export default ModalComponent.extend({
},
updateAllowedPlan(plan, isChecked) {
const portalPlans = this.settings.get('portalPlans') || [];
const portalPlans = this.settings.portalPlans || [];
const allowedPlans = [...portalPlans];
const freeTier = this.model.tiers.find(p => p.type === 'free');
if (!isChecked) {
this.settings.set('portalPlans', allowedPlans.filter(p => p !== plan));
this.settings.portalPlans = allowedPlans.filter(p => p !== plan);
if (plan === 'free') {
freeTier.set('visibility', 'none');
}
} else {
allowedPlans.push(plan);
this.settings.set('portalPlans', allowedPlans);
this.settings.portalPlans = allowedPlans;
if (plan === 'free') {
freeTier.set('visibility', 'public');
}
@ -303,12 +303,12 @@ export default ModalComponent.extend({
_validateSignupRedirect(url, type) {
let errMessage = `Please enter a valid URL`;
this.settings.get('errors').remove(type);
this.settings.get('hasValidated').removeObject(type);
this.settings.errors.remove(type);
this.settings.hasValidated.removeObject(type);
if (url === null) {
this.settings.get('errors').add(type, errMessage);
this.settings.get('hasValidated').pushObject(type);
this.settings.errors.add(type, errMessage);
this.settings.hasValidated.pushObject(type);
return false;
}
@ -319,9 +319,9 @@ export default ModalComponent.extend({
if (url.href.startsWith(this.siteUrl)) {
const path = url.href.replace(this.siteUrl, '');
this.settings.set(type, path);
this.settings[type] = path;
} else {
this.settings.set(type, url.href);
this.settings[type] = url.href;
}
},
@ -330,9 +330,9 @@ export default ModalComponent.extend({
await this.model.preloadTask;
}
const portalButtonIcon = this.settings.get('portalButtonIcon') || '';
const portalButtonIcon = this.settings.portalButtonIcon || '';
if (portalButtonIcon && !this.membersUtils.defaultIconKeys.includes(portalButtonIcon)) {
this.set('customIcon', this.settings.get('portalButtonIcon'));
this.set('customIcon', this.settings.portalButtonIcon);
}
this.siteUrl = this.config.get('blogUrl');
@ -360,7 +360,7 @@ export default ModalComponent.extend({
this.settings.errors.remove('members_support_address');
this.settings.hasValidated.removeObject('members_support_address');
if (this.settings.get('errors').length !== 0) {
if (this.settings.errors.length !== 0) {
return;
}
@ -374,14 +374,14 @@ export default ModalComponent.extend({
})
);
const newEmail = this.settings.get('membersSupportAddress');
const newEmail = this.settings.membersSupportAddress;
try {
const result = yield this.settings.save();
if (result._meta?.sent_email_verification) {
yield this.modals.open(ConfirmEmailModal, {
newEmail,
currentEmail: this.settings.get('membersSupportAddress')
currentEmail: this.settings.membersSupportAddress
});
}

View File

@ -11,14 +11,14 @@ export default class ModalStripeConnect extends ModalBase {
@action
setStripeConnectIntegrationTokenSetting(stripeConnectIntegrationToken) {
this.settings.set('stripeConnectIntegrationToken', stripeConnectIntegrationToken);
this.settings.stripeConnectIntegrationToken = stripeConnectIntegrationToken;
}
@action
reset() {
// stripeConnectIntegrationToken is not a persisted value so we don't want
// to keep it around across transitions
this.settings.set('stripeConnectIntegrationToken', undefined);
this.settings.stripeConnectIntegrationToken = undefined;
}
@action
@ -36,7 +36,7 @@ export default class ModalStripeConnect extends ModalBase {
@action
updateSuccessModifier() {
// Note, we should also check isStripeEnabled because stripeDirect option might be enabled
if (this.membersUtils.get('isStripeEnabled') && this.settings.get('stripeConnectAccountId')) {
if (this.membersUtils.get('isStripeEnabled') && this.settings.stripeConnectAccountId) {
if (this.modifier?.indexOf('stripe-connected') === -1) {
this.updateModifier(`${this.modifier} stripe-connected`);
}
@ -49,7 +49,7 @@ export default class ModalStripeConnect extends ModalBase {
actions = {
confirm() {
if (this.settings.get('stripeConnectAccountId')) {
if (this.settings.stripeConnectAccountId) {
return this.confirmAction();
}
// noop - enter key shouldn't do anything

View File

@ -86,7 +86,7 @@ export default class ModalTierPrice extends ModalBase {
if (this.tier.get('trialDays')) {
this.freeTrialEnabled = true;
}
this.accentColorStyle = htmlSafe(`color: ${this.settings.get('accentColor')}`);
this.accentColorStyle = htmlSafe(`color: ${this.settings.accentColor}`);
}
@action
@ -179,7 +179,7 @@ export default class ModalTierPrice extends ModalBase {
}
this.tier.set('benefits', this.benefits.filter(benefit => !benefit.get('isBlank')));
try {
yield this.tier.save();
this.hasSaved = true;

View File

@ -8,7 +8,7 @@ export default class EditNewsletterPreview extends Component {
@service settings;
get showHeader() {
return (this.args.newsletter.showHeaderIcon && this.settings.get('icon'))
return (this.args.newsletter.showHeaderIcon && this.settings.icon)
|| this.headerTitle;
}
@ -18,7 +18,7 @@ export default class EditNewsletterPreview extends Component {
get headerTitle() {
if (this.args.newsletter.showHeaderTitle) {
return this.settings.get('title');
return this.settings.title;
} else if (this.args.newsletter.showHeaderName) {
return this.args.newsletter.name;
}

View File

@ -33,7 +33,7 @@ export default class VerifyEmail extends Component {
yield this.ajax.put(url, {data: {token}});
yield this.settings.reload();
this.email = this.settings.get('membersSupportAddress');
this.email = this.settings.membersSupportAddress;
} catch (e) {
this.error = e.message;
}

View File

@ -27,7 +27,7 @@ export default class PostsListItemClicks extends Component {
let formattedTime = formatPostTime(
this.post.publishedAtUTC,
{timezone: this.settings.get('timezone'), scheduled: true}
{timezone: this.settings.timezone, scheduled: true}
);
text.push(formattedTime);

View File

@ -8,7 +8,7 @@ export default class AccentColorFormField extends Component {
@service settings;
get accentColor() {
const color = this.settings.get('accentColor');
const color = this.settings.accentColor;
if (color && color[0] === '#') {
return color.slice(1);
}
@ -16,7 +16,7 @@ export default class AccentColorFormField extends Component {
}
get accentColorPickerValue() {
return this.settings.get('accentColor') || '#ffffff';
return this.settings.accentColor || '#ffffff';
}
get accentColorBgStyle() {
@ -31,7 +31,7 @@ export default class AccentColorFormField extends Component {
@action
async updateAccentColor(event) {
let newColor = event.target.value;
const oldColor = this.settings.get('accentColor');
const oldColor = this.settings.accentColor;
// reset errors and validation
this.settings.errors.remove('accentColor');
@ -62,7 +62,7 @@ export default class AccentColorFormField extends Component {
return;
}
this.settings.set('accentColor', newColor);
this.settings.accentColor = newColor;
this.args.didUpdate('accentColor', newColor);
} else {
this.settings.errors.add('accentColor', 'Please enter a color in hex format');

View File

@ -25,7 +25,7 @@ export default class PublicationCoverFormField extends Component {
@action
update(value) {
this.settings.set('coverImage', value);
this.settings.coverImage = value;
this.args.didUpdate('coverImage', value);
}

View File

@ -21,7 +21,7 @@ export default class PublicationIconFormField extends Component {
@action
update(value) {
this.settings.set('icon', value);
this.settings.icon = value;
this.args.didUpdate('icon', value);
}
}

View File

@ -21,7 +21,7 @@ export default class PublicationLogoFormField extends Component {
@action
update(value) {
this.settings.set('logo', value);
this.settings.logo = value;
this.args.didUpdate('logo', value);
}
}

View File

@ -7,13 +7,13 @@ export default class SiteDescriptionFormField extends Component {
@action
update(event) {
this.settings.set('description', event.target.value);
this.settings.description = event.target.value;
}
@action
async validate(event) {
const value = event.target.value;
this.settings.set('description', value);
this.settings.description = value;
await this.settings.validate({property: 'description'});
this.args.didUpdate('description', value);
}

View File

@ -28,12 +28,12 @@ export default class SettingsMembersCommentAccess extends Component {
}
get selectedOption() {
return this.options.find(o => o.value === this.settings.get('commentsEnabled'));
return this.options.find(o => o.value === this.settings.commentsEnabled);
}
@action
setCommentAccess(option) {
this.settings.set('commentsEnabled', option.value);
this.settings.commentsEnabled = option.value;
this.args.onChange?.(option.value);
}
}

View File

@ -37,22 +37,22 @@ export default class SettingsMembersDefaultPostAccess extends Component {
}
get hasVisibilityFilter() {
return !['public', 'members', 'paid'].includes(this.settings.get('defaultContentVisibility'));
return !['public', 'members', 'paid'].includes(this.settings.defaultContentVisibility);
}
get visibilityTiers() {
const visibilityTiersData = this.settings.get('defaultContentVisibilityTiers');
const visibilityTiersData = this.settings.defaultContentVisibilityTiers;
return (visibilityTiersData || []).map((id) => {
return {id};
});
}
get selectedOption() {
if (this.settings.get('membersSignupAccess') === 'none') {
if (this.settings.membersSignupAccess === 'none') {
return this.options.find(o => o.value === 'public');
}
return this.options.find(o => o.value === this.settings.get('defaultContentVisibility'));
return this.options.find(o => o.value === this.settings.defaultContentVisibility);
}
@action
@ -61,21 +61,21 @@ export default class SettingsMembersDefaultPostAccess extends Component {
const tierIds = segment?.map((tier) => {
return tier.id;
});
this.settings.set('defaultContentVisibility', 'tiers');
this.settings.set('defaultContentVisibilityTiers', tierIds);
this.settings.defaultContentVisibility = 'tiers';
this.settings.defaultContentVisibilityTiers = tierIds;
this.showSegmentError = false;
} else {
this.settings.set('defaultContentVisibility', '');
this.settings.defaultContentVisibility = '';
this.showSegmentError = true;
}
}
@action
setDefaultContentVisibility(option) {
if (this.settings.get('membersSignupAccess') !== 'none') {
this.settings.set('defaultContentVisibility', option.value);
if (this.settings.membersSignupAccess !== 'none') {
this.settings.defaultContentVisibility = option.value;
if (option.value === 'tiers') {
this.settings.set('defaultContentVisibilityTiers', []);
this.settings.defaultContentVisibilityTiers = [];
}
}
}

View File

@ -28,16 +28,16 @@ export default class SettingsMembersSubscriptionAccess extends Component {
}
get selectedOption() {
return this.options.find(o => o.value === this.settings.get('membersSignupAccess'));
return this.options.find(o => o.value === this.settings.membersSignupAccess);
}
@action
setSignupAccess(option) {
this.settings.set('membersSignupAccess', option.value);
this.settings.membersSignupAccess = option.value;
this.args.onChange?.(option.value);
if (option.value === 'none') {
this.settings.set('defaultContentVisibility', 'public');
this.settings.defaultContentVisibility = 'public';
}
}
}

View File

@ -57,20 +57,20 @@ export default class StripeSettingsForm extends Component {
/** OLD **/
get stripeDirectPublicKey() {
return this.settings.get('stripePublishableKey');
return this.settings.stripePublishableKey;
}
get stripeDirectSecretKey() {
return this.settings.settings.get('stripeSecretKey');
return this.settings.stripeSecretKey;
}
get stripeConnectAccountId() {
return this.settings.get('stripeConnectAccountId');
return this.settings.stripeConnectAccountId;
}
get stripeConnectAccountName() {
return this.settings.get('stripeConnectDisplayName');
return this.settings.stripeConnectDisplayName;
}
get stripeConnectLivemode() {
return this.settings.get('stripeConnectLivemode');
return this.settings.stripeConnectLivemode;
}
get selectedCurrency() {
@ -79,7 +79,7 @@ export default class StripeSettingsForm extends Component {
}
get stripePlans() {
const plans = this.settings.get('stripePlans');
const plans = this.settings.stripePlans;
const monthly = plans.find(plan => plan.interval === 'month');
const yearly = plans.find(plan => plan.interval === 'year' && plan.name !== 'Complimentary');
@ -112,14 +112,14 @@ export default class StripeSettingsForm extends Component {
@action
setStripeDirectPublicKey(event) {
this.settings.set('stripeProductName', this.settings.get('title'));
this.settings.set('stripePublishableKey', event.target.value);
this.settings.stripeProductName = this.settings.title;
this.settings.stripePublishableKey = event.target.value;
}
@action
setStripeDirectSecretKey(event) {
this.settings.set('stripeProductName', this.settings.get('title'));
this.settings.set('stripeSecretKey', event.target.value);
this.settings.stripeProductName = this.settings.title;
this.settings.stripeSecretKey = event.target.value;
}
@action
@ -130,7 +130,7 @@ export default class StripeSettingsForm extends Component {
@action
setStripePlansCurrency(event) {
const newCurrency = event.value;
const updatedPlans = this.settings.get('stripePlans').map((plan) => {
const updatedPlans = this.settings.stripePlans.map((plan) => {
if (plan.name !== 'Complimentary') {
return Object.assign({}, plan, {
currency: newCurrency
@ -152,7 +152,7 @@ export default class StripeSettingsForm extends Component {
});
}
this.settings.set('stripePlans', updatedPlans);
this.settings.stripePlans = updatedPlans;
this._scratchStripeYearlyAmount = null;
this._scratchStripeMonthlyAmount = null;
this.validateStripePlans();
@ -160,7 +160,7 @@ export default class StripeSettingsForm extends Component {
@action
setStripeConnectIntegrationToken(event) {
this.settings.set('stripeProductName', this.settings.get('title'));
this.settings.stripeProductName = this.settings.title;
this.args.setStripeConnectIntegrationTokenSetting(event.target.value);
}
@ -183,13 +183,13 @@ export default class StripeSettingsForm extends Component {
updateStripeDirect() {
// Allow disabling stripe direct keys if stripe is still enabled, while the config is disabled
this.stripeDirect = this.config.get('stripeDirect')
|| (this.membersUtils.isStripeEnabled && !this.settings.get('stripeConnectAccountId'));
|| (this.membersUtils.isStripeEnabled && !this.settings.stripeConnectAccountId);
}
@action
validateStripePlans() {
this.settings.get('errors').remove('stripePlans');
this.settings.get('hasValidated').removeObject('stripePlans');
this.settings.errors.remove('stripePlans');
this.settings.hasValidated.removeObject('stripePlans');
if (this._scratchStripeYearlyAmount === null) {
this._scratchStripeYearlyAmount = this.stripePlans.yearly.amount;
@ -203,7 +203,7 @@ export default class StripeSettingsForm extends Component {
const yearlyAmount = parseInt(this._scratchStripeYearlyAmount);
const monthlyAmount = parseInt(this._scratchStripeMonthlyAmount);
if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) {
const minimum = Intl.NumberFormat(this.settings.get('locale'), {
const minimum = Intl.NumberFormat(this.settings.locale, {
currency: selectedCurrency.isoCode,
style: 'currency'
}).format(1);
@ -211,7 +211,7 @@ export default class StripeSettingsForm extends Component {
throw new TypeError(`Subscription amount must be at least ${minimum}`);
}
const updatedPlans = this.settings.get('stripePlans').map((plan) => {
const updatedPlans = this.settings.stripePlans.map((plan) => {
if (plan.name !== 'Complimentary') {
let newAmount;
if (plan.interval === 'year') {
@ -226,11 +226,11 @@ export default class StripeSettingsForm extends Component {
return plan;
});
this.settings.set('stripePlans', updatedPlans);
this.settings.stripePlans = updatedPlans;
} catch (err) {
this.settings.get('errors').add('stripePlans', err.message);
this.settings.errors.add('stripePlans', err.message);
} finally {
this.settings.get('hasValidated').pushObject('stripePlans');
this.settings.hasValidated.pushObject('stripePlans');
}
}
@ -296,12 +296,12 @@ export default class StripeSettingsForm extends Component {
*saveStripeSettingsTask() {
this.stripeConnectError = null;
if (this.settings.get('stripeConnectIntegrationToken')) {
if (this.settings.stripeConnectIntegrationToken) {
try {
let response = yield this.settings.save();
yield this.saveTier.perform();
this.settings.set('portalPlans', ['free', 'monthly', 'yearly']);
this.settings.portalPlans = ['free', 'monthly', 'yearly'];
response = yield this.settings.save();

View File

@ -20,46 +20,46 @@ export default class Newsletters extends Component {
mailgunRegions = [US, EU];
get emailNewsletterEnabled() {
return this.settings.get('editorDefaultEmailRecipients') !== 'disabled';
return this.settings.editorDefaultEmailRecipients !== 'disabled';
}
get mailgunRegion() {
if (!this.settings.get('mailgunBaseUrl')) {
if (!this.settings.mailgunBaseUrl) {
return US;
}
return [US, EU].find((region) => {
return region.baseUrl === this.settings.get('mailgunBaseUrl');
return region.baseUrl === this.settings.mailgunBaseUrl;
});
}
get mailgunSettings() {
return {
apiKey: this.settings.get('mailgunApiKey') || '',
domain: this.settings.get('mailgunDomain') || '',
baseUrl: this.settings.get('mailgunBaseUrl') || ''
apiKey: this.settings.mailgunApiKey || '',
domain: this.settings.mailgunDomain || '',
baseUrl: this.settings.mailgunBaseUrl || ''
};
}
@action
setMailgunDomain(event) {
this.settings.set('mailgunDomain', event.target.value);
if (!this.settings.get('mailgunBaseUrl')) {
this.settings.set('mailgunBaseUrl', this.mailgunRegion.baseUrl);
this.settings.mailgunDomain = event.target.value;
if (!this.settings.mailgunBaseUrl) {
this.settings.mailgunBaseUrl = this.mailgunRegion.baseUrl;
}
}
@action
setMailgunApiKey(event) {
this.settings.set('mailgunApiKey', event.target.value);
if (!this.settings.get('mailgunBaseUrl')) {
this.settings.set('mailgunBaseUrl', this.mailgunRegion.baseUrl);
this.settings.mailgunApiKey = event.target.value;
if (!this.settings.mailgunBaseUrl) {
this.settings.mailgunBaseUrl = this.mailgunRegion.baseUrl;
}
}
@action
setMailgunRegion(region) {
this.settings.set('mailgunBaseUrl', region.baseUrl);
this.settings.mailgunBaseUrl = region.baseUrl;
}
@action
@ -67,7 +67,7 @@ export default class Newsletters extends Component {
if (event) {
event.preventDefault();
}
this.settings.set('emailTrackOpens', !this.settings.get('emailTrackOpens'));
this.settings.emailTrackOpens = !this.settings.emailTrackOpens;
}
@action
@ -75,7 +75,7 @@ export default class Newsletters extends Component {
if (event) {
event.preventDefault();
}
this.settings.set('emailTrackClicks', !this.settings.get('emailTrackClicks'));
this.settings.emailTrackClicks = !this.settings.emailTrackClicks;
}
@action
@ -87,10 +87,10 @@ export default class Newsletters extends Component {
const newsletterEnabled = !this.emailNewsletterEnabled;
if (newsletterEnabled) {
this.settings.set('editorDefaultEmailRecipients', 'visibility');
this.settings.editorDefaultEmailRecipients = 'visibility';
} else {
this.settings.set('editorDefaultEmailRecipients', 'disabled');
this.settings.set('editorDefaultEmailRecipientsFilter', null);
this.settings.editorDefaultEmailRecipients = 'disabled';
this.settings.editorDefaultEmailRecipientsFilter = null;
}
this.recipientsSelectValue = this._getDerivedRecipientsSelectValue();
@ -106,22 +106,22 @@ export default class Newsletters extends Component {
// Update the underlying setting properties to match the selected recipients option
if (['visibility', 'disabled'].includes(value)) {
this.settings.set('editorDefaultEmailRecipients', value);
this.settings.set('editorDefaultEmailRecipientsFilter', null);
this.settings.editorDefaultEmailRecipients = value;
this.settings.editorDefaultEmailRecipientsFilter = null;
} else {
this.settings.set('editorDefaultEmailRecipients', 'filter');
this.settings.editorDefaultEmailRecipients = 'filter';
}
if (value === 'all-members') {
this.settings.set('editorDefaultEmailRecipientsFilter', 'status:free,status:-free');
this.settings.editorDefaultEmailRecipientsFilter = 'status:free,status:-free';
}
if (value === 'paid-only') {
this.settings.set('editorDefaultEmailRecipientsFilter', 'status:-free');
this.settings.editorDefaultEmailRecipientsFilter = 'status:-free';
}
if (value === 'none') {
this.settings.set('editorDefaultEmailRecipientsFilter', null);
this.settings.editorDefaultEmailRecipientsFilter = null;
}
// Update the value used to display the selected recipients option explicitly
@ -131,12 +131,12 @@ export default class Newsletters extends Component {
@action
setDefaultEmailRecipientsFilter(filter) {
this.settings.set('editorDefaultEmailRecipientsFilter', filter);
this.settings.editorDefaultEmailRecipientsFilter = filter;
}
_getDerivedRecipientsSelectValue() {
const defaultEmailRecipients = this.settings.get('editorDefaultEmailRecipients');
const defaultEmailRecipientsFilter = this.settings.get('editorDefaultEmailRecipientsFilter');
const defaultEmailRecipients = this.settings.editorDefaultEmailRecipients;
const defaultEmailRecipientsFilter = this.settings.editorDefaultEmailRecipientsFilter;
if (defaultEmailRecipients === 'filter') {
if (defaultEmailRecipientsFilter === 'status:free,status:-free') {

View File

@ -21,7 +21,7 @@ export default class TagForm extends Component {
@tracked codeInjectionOpen = false;
get seoTitle() {
const settingsTitle = this.settings.get('title') || '';
const settingsTitle = this.settings.title || '';
const tagName = settingsTitle ? `${this.args.tag.name} - ${settingsTitle}` : this.args.tag.name;
let metaTitle = this.args.tag.metaTitle || tagName;
@ -74,7 +74,7 @@ export default class TagForm extends Component {
}
get twitterDescription() {
return this.args.tag.twitterDescription || this.seoDescription || this.settings.get('metaDescription') || '';
return this.args.tag.twitterDescription || this.seoDescription || this.settings.metaDescription || '';
}
get twitterImage() {
@ -86,7 +86,7 @@ export default class TagForm extends Component {
}
get facebookDescription() {
return this.args.tag.facebookDescription || this.seoDescription || this.settings.get('metaDescription') || '';
return this.args.tag.facebookDescription || this.seoDescription || this.settings.metaDescription || '';
}
get facebookImage() {

View File

@ -1039,7 +1039,7 @@ export default class EditorController extends Controller {
emailOnly,
newsletter
} = this.post;
let publishedAtBlogTZ = moment.tz(publishedAtUTC, this.settings.get('timezone'));
let publishedAtBlogTZ = moment.tz(publishedAtUTC, this.settings.timezone);
let title = 'Scheduled';
let description = emailOnly ? ['Will be sent'] : ['Will be published'];

View File

@ -1035,7 +1035,7 @@ export default class LexicalEditorController extends Controller {
emailOnly,
newsletter
} = this.post;
let publishedAtBlogTZ = moment.tz(publishedAtUTC, this.settings.get('timezone'));
let publishedAtBlogTZ = moment.tz(publishedAtUTC, this.settings.timezone);
let title = 'Scheduled';
let description = emailOnly ? ['Will be sent'] : ['Will be published'];

View File

@ -24,7 +24,7 @@ export default class MembersActivityController extends Controller {
hiddenEvents.push(...EMAIL_EVENTS);
}
if (this.settings.get('editorDefaultEmailRecipients') === 'disabled') {
if (this.settings.editorDefaultEmailRecipients === 'disabled') {
hiddenEvents.push(...EMAIL_EVENTS, ...NEWSLETTER_EVENTS);
}

View File

@ -35,7 +35,7 @@ export default class SettingsDesignIndexController extends Controller {
@task
*saveTask() {
try {
if (this.settings.get('errors').length !== 0) {
if (this.settings.errors.length !== 0) {
return;
}

View File

@ -39,7 +39,7 @@ export default class GeneralController extends Controller {
@computed('config.blogUrl', 'settings.publicHash')
get privateRSSUrl() {
let blogUrl = this.get('config.blogUrl');
let publicHash = this.get('settings.publicHash');
let publicHash = this.settings.publicHash;
return `${blogUrl}/${publicHash}/rss`;
}
@ -51,13 +51,13 @@ export default class GeneralController extends Controller {
@action
setTimezone(timezone) {
this.set('settings.timezone', timezone.name);
this.settings.timezone = timezone.name;
}
@action
removeImage(image) {
// setting `null` here will error as the server treats it as "null"
this.settings.set(image, '');
this.settings[image] = '';
}
/**
@ -80,7 +80,7 @@ export default class GeneralController extends Controller {
@action
imageUploaded(property, results) {
if (results[0]) {
return this.settings.set(property, results[0].url);
return this.settings[property] = results[0].url;
}
}
@ -88,18 +88,18 @@ export default class GeneralController extends Controller {
toggleIsPrivate(isPrivate) {
let settings = this.settings;
settings.set('isPrivate', isPrivate);
settings.get('errors').remove('password');
settings.isPrivate = isPrivate;
settings.errors.remove('password');
let changedAttrs = settings.changedAttributes();
// set a new random password when isPrivate is enabled
if (isPrivate && changedAttrs.isPrivate) {
settings.set('password', randomPassword());
settings.password = randomPassword();
// reset the password when isPrivate is disabled
} else if (changedAttrs.password) {
settings.set('password', changedAttrs.password[0]);
settings.password = changedAttrs.password[0];
}
}
@ -135,7 +135,7 @@ export default class GeneralController extends Controller {
this.clearScratchValues();
config.set('blogTitle', settings.get('title'));
config.set('blogTitle', settings.title);
if (changedAttrs.password) {
this.frontend.loginIfNeeded();

View File

@ -9,7 +9,7 @@ export default class AmpController extends Controller {
@action
update(value) {
this.settings.set('amp', value);
this.settings.amp = value;
}
@action

View File

@ -9,7 +9,7 @@ export default class FirstpromoterController extends Controller {
@action
update(value) {
this.settings.set('firstpromoter', value);
this.settings.firstpromoter = value;
}
@action

View File

@ -11,7 +11,7 @@ export default class SlackController extends Controller {
@service settings;
get testNotificationDisabled() {
const slackUrl = this.settings.get('slackUrl');
const slackUrl = this.settings.slackUrl;
return !slackUrl;
}

View File

@ -9,7 +9,7 @@ export default class UnsplashController extends Controller {
@action
update(value) {
this.settings.set('unsplash', value);
this.settings.unsplash = value;
}
@action

View File

@ -119,7 +119,7 @@ export default class LabsController extends Controller {
// reload settings
return this.settings.reload().then((settings) => {
this.feature.fetch();
this.config.set('blogTitle', settings.get('title'));
this.config.set('blogTitle', settings.title);
});
});
}).catch((response) => {

View File

@ -94,7 +94,7 @@ export default class MembersAccessController extends Controller {
}
get isDirty() {
return this.settings.get('hasDirtyAttributes') || this.hasChangedPrices;
return this.settings.hasDirtyAttributes || this.hasChangedPrices;
}
@action
@ -239,7 +239,7 @@ export default class MembersAccessController extends Controller {
// TODO: can these be worked out from settings in membersUtils?
const monthlyPrice = Math.round(this.stripeMonthlyAmount * 100);
const yearlyPrice = Math.round(this.stripeYearlyAmount * 100);
let portalPlans = this.settings.get('portalPlans') || [];
let portalPlans = this.settings.portalPlans || [];
let isMonthlyChecked = portalPlans.includes('monthly');
let isYearlyChecked = portalPlans.includes('yearly');
@ -339,11 +339,11 @@ export default class MembersAccessController extends Controller {
@task({drop: true})
*saveSettingsTask(options) {
if (this.settings.get('errors').length !== 0) {
if (this.settings.errors.length !== 0) {
return;
}
// When no filer is selected in `Specific tier(s)` option
if (!this.settings.get('defaultContentVisibility')) {
if (!this.settings.defaultContentVisibility) {
return;
}
const result = yield this.settings.save();
@ -353,7 +353,7 @@ export default class MembersAccessController extends Controller {
}
async saveTier() {
const paidMembersEnabled = this.settings.get('paidMembersEnabled');
const paidMembersEnabled = this.settings.paidMembersEnabled;
if (this.tier && paidMembersEnabled) {
const monthlyAmount = Math.round(this.stripeMonthlyAmount * 100);
const yearlyAmount = Math.round(this.stripeYearlyAmount * 100);
@ -385,12 +385,12 @@ export default class MembersAccessController extends Controller {
_validateSignupRedirect(url, type) {
const siteUrl = this.config.get('blogUrl');
let errMessage = `Please enter a valid URL`;
this.settings.get('errors').remove(type);
this.settings.get('hasValidated').removeObject(type);
this.settings.errors.remove(type);
this.settings.hasValidated.removeObject(type);
if (url === null) {
this.settings.get('errors').add(type, errMessage);
this.settings.get('hasValidated').pushObject(type);
this.settings.errors.add(type, errMessage);
this.settings.hasValidated.pushObject(type);
return false;
}
@ -401,9 +401,9 @@ export default class MembersAccessController extends Controller {
if (url.href.startsWith(siteUrl)) {
const path = url.href.replace(siteUrl, '');
this.settings.set(type, path);
this.settings[type] = path;
} else {
this.settings.set(type, url.href);
this.settings[type] = url.href;
}
}
}

View File

@ -56,7 +56,7 @@ export default class NavigationController extends Controller {
return;
}
let navItems = item.isSecondary ? this.get('settings.secondaryNavigation') : this.get('settings.navigation');
let navItems = item.isSecondary ? this.settings.secondaryNavigation : this.settings.navigation;
navItems.removeObject(item);
this.set('dirtyAttributes', true);
@ -95,7 +95,7 @@ export default class NavigationController extends Controller {
}
addNewNavItem(item) {
let navItems = item.isSecondary ? this.get('settings.secondaryNavigation') : this.get('settings.navigation');
let navItems = item.isSecondary ? this.settings.secondaryNavigation : this.settings.navigation;
item.set('isNew', false);
navItems.pushObject(item);
@ -112,8 +112,8 @@ export default class NavigationController extends Controller {
@task
*saveTask() {
let navItems = this.get('settings.navigation');
let secondaryNavItems = this.get('settings.secondaryNavigation');
let navItems = this.settings.navigation;
let secondaryNavItems = this.settings.secondaryNavigation;
let notifications = this.notifications;
let validationPromises = [];

View File

@ -170,7 +170,7 @@ export default class TierController extends Controller {
if (this.tier.get('errors').length !== 0) {
return;
}
if (this.settings.get('errors').length !== 0) {
if (this.settings.errors.length !== 0) {
return;
}
yield this.settings.save();
@ -183,12 +183,12 @@ export default class TierController extends Controller {
_validateSignupRedirect(url, type) {
let errMessage = `Please enter a valid URL`;
this.settings.get('errors').remove(type);
this.settings.get('hasValidated').removeObject(type);
this.settings.errors.remove(type);
this.settings.hasValidated.removeObject(type);
if (url === null) {
this.settings.get('errors').add(type, errMessage);
this.settings.get('hasValidated').pushObject(type);
this.settings.errors.add(type, errMessage);
this.settings.hasValidated.pushObject(type);
return false;
}
@ -199,9 +199,9 @@ export default class TierController extends Controller {
if (url.href.startsWith(this.siteUrl)) {
const path = url.href.replace(this.siteUrl, '');
this.settings.set(type, path);
this.settings[type] = path;
} else {
this.settings.set(type, url.href);
this.settings[type] = url.href;
}
}
}

View File

@ -1,11 +1,10 @@
import Helper from '@ember/component/helper';
import {get} from '@ember/object';
import {inject as service} from '@ember/service';
export default class GetSetting extends Helper {
@service settings;
compute([key = '']) {
return get(this.settings, key);
return this.settings[key];
}
}

View File

@ -59,6 +59,6 @@ export default class GhFormatPostTimeHelper extends Helper {
compute([timeago], options) {
assert('You must pass a time to the gh-format-post-time helper', timeago);
return formatPostTime(timeago, Object.assign({}, options, {timezone: this.settings.get('timezone')}));
return formatPostTime(timeago, Object.assign({}, options, {timezone: this.settings.timezone}));
}
}

View File

@ -6,8 +6,8 @@ export default class IsMomentToday extends Helper {
@service settings;
compute([date]) {
const today = moment().tz(this.settings.get('timezone'));
const dateMoment = moment.tz(date, this.settings.get('timezone'));
const today = moment().tz(this.settings.timezone);
const dateMoment = moment.tz(date, this.settings.timezone);
return dateMoment.isSame(today, 'day');
}

View File

@ -17,10 +17,10 @@ export default class MembersEventFilter extends Helper {
) {
const excludedEventsSet = new Set();
if (this.settings.get('editorDefaultEmailRecipients') === 'disabled') {
if (this.settings.editorDefaultEmailRecipients === 'disabled') {
[...EMAIL_EVENTS, ...NEWSLETTER_EVENTS].forEach(type => excludedEventsSet.add(type));
}
if (this.settings.get('commentsEnabled') === 'off') {
if (this.settings.commentsEnabled === 'off') {
excludedEventsSet.add('comment_event');
}

View File

@ -6,6 +6,6 @@ export default class MomentSiteTz extends Helper {
@service settings;
compute([date]) {
return moment.tz(date, this.settings.get('timezone'));
return moment.tz(date, this.settings.timezone);
}
}

View File

@ -185,39 +185,39 @@ export default Model.extend(Comparable, ValidationEngine, {
hasBeenEmailed: computed('isPost', 'isSent', 'isPublished', 'email', function () {
return this.isPost
&& (this.isSent || this.isPublished)
&& (this.isSent || this.isPublished)
&& this.email && this.email.status !== 'failed';
}),
didEmailFail: computed('isPost', 'isSent', 'isPublished', 'email.status', function () {
return this.isPost
&& (this.isSent || this.isPublished)
&& (this.isSent || this.isPublished)
&& this.email && this.email.status === 'failed';
}),
showEmailOpenAnalytics: computed('hasBeenEmailed', 'isSent', 'isPublished', function () {
return this.hasBeenEmailed
&& !this.session.user.isContributor
&& this.settings.get('membersSignupAccess') !== 'none'
&& this.settings.get('editorDefaultEmailRecipients') !== 'disabled'
&& this.settings.membersSignupAccess !== 'none'
&& this.settings.editorDefaultEmailRecipients !== 'disabled'
&& this.hasBeenEmailed
&& this.email.trackOpens
&& this.settings.get('emailTrackOpens');
&& this.settings.emailTrackOpens;
}),
showEmailClickAnalytics: computed('hasBeenEmailed', 'isSent', 'isPublished', 'email', function () {
return this.hasBeenEmailed
&& !this.session.user.isContributor
&& this.settings.get('membersSignupAccess') !== 'none'
&& this.settings.get('editorDefaultEmailRecipients') !== 'disabled'
&& (this.isSent || this.isPublished)
&& this.settings.membersSignupAccess !== 'none'
&& this.settings.editorDefaultEmailRecipients !== 'disabled'
&& (this.isSent || this.isPublished)
&& this.email.trackClicks
&& this.settings.get('emailTrackClicks');
&& this.settings.emailTrackClicks;
}),
showAttributionAnalytics: computed('isPage', 'emailOnly', 'isPublished', 'membersUtils.isMembersInviteOnly', function () {
return (this.isPage || !this.emailOnly)
&& this.isPublished
return (this.isPage || !this.emailOnly)
&& this.isPublished
&& this.feature.get('memberAttribution')
&& !this.membersUtils.isMembersInviteOnly
&& !this.session.user.isContributor;
@ -233,7 +233,7 @@ export default Model.extend(Comparable, ValidationEngine, {
|| this.showAttributionAnalytics
);
}),
previewUrl: computed('uuid', 'ghostPaths.url', 'config.blogUrl', function () {
let blogUrl = this.get('config.blogUrl');
let uuid = this.uuid;
@ -252,7 +252,7 @@ export default Model.extend(Comparable, ValidationEngine, {
visibilitySegment: computed('visibility', 'isPublic', 'tiers', function () {
if (this.isPublic) {
return this.settings.get('defaultContentVisibility') === 'paid' ? 'status:-free' : 'status:free,status:-free';
return this.settings.defaultContentVisibility === 'paid' ? 'status:-free' : 'status:free,status:-free';
} else {
if (this.visibility === 'members') {
return 'status:free,status:-free';
@ -321,7 +321,7 @@ export default Model.extend(Comparable, ValidationEngine, {
let publishedAtUTC = this.publishedAtUTC;
let publishedAtBlogDate = this.publishedAtBlogDate;
let publishedAtBlogTime = this.publishedAtBlogTime;
let blogTimezone = this.get('settings.timezone');
let blogTimezone = this.settings.timezone;
if (!publishedAtUTC && isBlank(publishedAtBlogDate) && isBlank(publishedAtBlogTime)) {
return null;
@ -362,7 +362,7 @@ export default Model.extend(Comparable, ValidationEngine, {
_setPublishedAtBlogStrings(momentDate) {
if (momentDate) {
let blogTimezone = this.get('settings.timezone');
let blogTimezone = this.settings.timezone;
let publishedAtBlog = moment.tz(momentDate, blogTimezone);
this.set('publishedAtBlogDate', publishedAtBlog.format('YYYY-MM-DD'));

View File

@ -1,7 +1,5 @@
/* eslint-disable camelcase */
import Model, {attr} from '@ember-data/model';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import {and} from '@ember/object/computed';
export default Model.extend(ValidationEngine, {
validationType: 'setting',
@ -84,8 +82,6 @@ export default Model.extend(ValidationEngine, {
editorDefaultEmailRecipientsFilter: attr('members-segment-string'),
emailVerificationRequired: attr('boolean'),
mailgunIsConfigured: and('mailgunApiKey', 'mailgunDomain', 'mailgunBaseUrl'),
// HACK - not a real model attribute but a workaround for Ember Data not
// exposing meta from save responses
_meta: attr()

View File

@ -45,7 +45,7 @@ export default class CodeInjectionRoute extends AdminRoute {
async confirmUnsavedChanges() {
const settings = this.settings;
if (settings.get('hasDirtyAttributes')) {
if (settings.hasDirtyAttributes) {
this.confirmModal = this.modals
.open(ConfirmUnsavedChangesModal)
.finally(() => {

View File

@ -36,7 +36,7 @@ export default class SettingsDesignIndexRoute extends AuthenticatedRoute {
}
confirmUnsavedChanges() {
if (!this.settings.get('hasDirtyAttributes') && !this.customThemeSettings.isDirty) {
if (!this.settings.hasDirtyAttributes && !this.customThemeSettings.isDirty) {
return Promise.resolve(true);
}

View File

@ -52,7 +52,7 @@ export default class GeneralSettingsRoute extends AdminRoute {
}
async confirmUnsavedChanges() {
if (this.settings.get('hasDirtyAttributes')) {
if (this.settings.hasDirtyAttributes) {
this.confirmModal = this.modals
.open(ConfirmUnsavedChangesModal)
.finally(() => {

View File

@ -43,7 +43,7 @@ export default class AMPRoute extends AdminRoute {
}
async confirmUnsavedChanges() {
if (this.settings.get('hasDirtyAttributes')) {
if (this.settings.hasDirtyAttributes) {
this.confirmModal = this.modals
.open(ConfirmUnsavedChangesModal)
.finally(() => {

View File

@ -43,7 +43,7 @@ export default class FirstPromotionIntegrationRoute extends AdminRoute {
}
async confirmUnsavedChanges() {
if (this.settings.get('hasDirtyAttributes')) {
if (this.settings.hasDirtyAttributes) {
this.confirmModal = this.modals
.open(ConfirmUnsavedChangesModal)
.finally(() => {

View File

@ -43,7 +43,7 @@ export default class SlackIntegrationRoute extends AdminRoute {
}
async confirmUnsavedChanges() {
if (this.settings.get('hasDirtyAttributes')) {
if (this.settings.hasDirtyAttributes) {
this.confirmModal = this.modals
.open(ConfirmUnsavedChangesModal)
.finally(() => {

View File

@ -43,7 +43,7 @@ export default class UnsplashIntegrationRoute extends AdminRoute {
}
async confirmUnsavedChanges() {
if (this.settings.get('hasDirtyAttributes')) {
if (this.settings.hasDirtyAttributes) {
this.confirmModal = this.modals
.open(ConfirmUnsavedChangesModal)
.finally(() => {

View File

@ -58,7 +58,7 @@ export default class MembersEmailLabsRoute extends AdminRoute {
}
confirmUnsavedChanges() {
if (!this.settings.get('hasDirtyAttributes')) {
if (!this.settings.hasDirtyAttributes) {
return Promise.resolve(true);
}

View File

@ -3,9 +3,7 @@ import EmberObject, {action} from '@ember/object';
import Service, {inject as service} from '@ember/service';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import {isArray} from '@ember/array';
import {observes} from '@ember-decorators/object';
import {task} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';
const VIEW_COLORS = [
'midgrey',
@ -108,33 +106,23 @@ export default class CustomViewsService extends Service {
@service session;
@service settings;
@tracked viewList = [];
constructor() {
super(...arguments);
this.updateViewList();
}
// eslint-disable-next-line ghost/ember/no-observers
@observes('settings.sharedViews', 'session.{isAuthenticated,user}')
async updateViewList() {
get viewList() {
let {settings, session} = this;
// avoid fetching user before authenticated otherwise the 403 can fire
// during authentication and cause errors during setup/signin
if (!session.isAuthenticated || !session.user) {
return;
return [];
}
let views = JSON.parse(settings.get('sharedViews') || '[]');
let views = JSON.parse(settings.sharedViews || '[]');
views = isArray(views) ? views : [];
let viewList = [];
const viewList = [];
// contributors can only see their own draft posts so it doesn't make
// sense to show them default views which change the status/type filter
let user = await session.user;
if (!user.isContributor) {
if (!session.user.isContributor) {
viewList.push(...DEFAULT_VIEWS);
}
@ -142,15 +130,17 @@ export default class CustomViewsService extends Service {
return CustomView.create(view);
}));
this.viewList = viewList;
return viewList;
}
@task
*saveViewTask(view) {
yield view.validate();
const {viewList} = this;
// perform some ad-hoc validation of duplicate names because ValidationEngine doesn't support it
let duplicateView = this.viewList.find((existingView) => {
let duplicateView = viewList.find((existingView) => {
return existingView.route === view.route
&& existingView.name.trim().toLowerCase() === view.name.trim().toLowerCase()
&& !isFilterEqual(existingView.filter, view.filter);
@ -165,15 +155,15 @@ export default class CustomViewsService extends Service {
// remove an older version of the view from our views list
// - we don't allow editing the filter and route+filter combos are unique
// - we create a new instance of a view from an existing one when editing to act as a "scratch" view
let matchingView = this.viewList.find(existingView => isViewEqual(existingView, view));
let matchingView = viewList.find(existingView => isViewEqual(existingView, view));
if (matchingView) {
this.viewList.replace(this.viewList.indexOf(matchingView), 1, [view]);
viewList.replace(viewList.indexOf(matchingView), 1, [view]);
} else {
this.viewList.push(view);
viewList.push(view);
}
// rebuild the "views" array in our user settings json string
yield this._saveViewSettings();
yield this._saveViewSettings(viewList);
view.set('isNew', false);
return view;
@ -181,10 +171,11 @@ export default class CustomViewsService extends Service {
@task
*deleteViewTask(view) {
let matchingView = this.viewList.find(existingView => isViewEqual(existingView, view));
const {viewList} = this;
let matchingView = viewList.find(existingView => isViewEqual(existingView, view));
if (matchingView && !matchingView.isDefault) {
this.viewList.removeObject(matchingView);
yield this._saveViewSettings();
viewList.removeObject(matchingView);
yield this._saveViewSettings(viewList);
return true;
}
}
@ -234,9 +225,9 @@ export default class CustomViewsService extends Service {
});
}
async _saveViewSettings() {
let sharedViews = this.viewList.reject(view => view.isDefault).map(view => view.toJSON());
this.settings.set('sharedViews', JSON.stringify(sharedViews));
async _saveViewSettings(viewList) {
let sharedViews = viewList.reject(view => view.isDefault).map(view => view.toJSON());
this.settings.sharedViews = JSON.stringify(sharedViews);
return this.settings.save();
}
}

View File

@ -366,7 +366,7 @@ export default class DashboardStatsService extends Service {
this.siteStatus = {
hasPaidTiers,
hasMultipleTiers: hasPaidTiers && this.activePaidTiers.length > 1,
newslettersEnabled: this.settings.get('editorDefaultEmailRecipients') !== 'disabled',
newslettersEnabled: this.settings.editorDefaultEmailRecipients !== 'disabled',
membersEnabled: this.membersUtils.isMembersEnabled
};
}

View File

@ -71,7 +71,7 @@ export default class FeatureService extends Service {
@computed('settings.labs')
get labs() {
let labs = this.get('settings.labs');
let labs = this.settings.labs;
try {
return JSON.parse(labs) || {};

View File

@ -11,7 +11,7 @@ export default class FrontendService extends Service {
_lastPassword = null;
get hasPasswordChanged() {
return this._lastPassword !== this.settings.get('password');
return this._lastPassword !== this.settings.password;
}
getUrl(path) {
@ -23,9 +23,9 @@ export default class FrontendService extends Service {
}
async loginIfNeeded() {
if (this.settings.get('isPrivate') && (this.hasPasswordChanged || !this._hasLoggedIn)) {
if (this.settings.isPrivate && (this.hasPasswordChanged || !this._hasLoggedIn)) {
const privateLoginUrl = this.getUrl('/private/?r=%2F');
this._lastPassword = this.settings.get('password');
this._lastPassword = this.settings.password;
return fetch(privateLoginUrl, {
method: 'POST',

View File

@ -7,15 +7,15 @@ export default class MembersUtilsService extends Service {
@service store;
get isMembersEnabled() {
return this.settings.get('membersEnabled');
return this.settings.membersEnabled;
}
get paidMembersEnabled() {
return this.settings.get('paidMembersEnabled');
return this.settings.paidMembersEnabled;
}
get isMembersInviteOnly() {
return this.settings.get('membersInviteOnly');
return this.settings.membersInviteOnly;
}
/**
@ -24,8 +24,8 @@ export default class MembersUtilsService extends Service {
get isStripeEnabled() {
const stripeDirect = this.config.get('stripeDirect');
const hasDirectKeys = !!this.settings.get('stripeSecretKey') && !!this.settings.get('stripePublishableKey');
const hasConnectKeys = !!this.settings.get('stripeConnectSecretKey') && !!this.settings.get('stripeConnectPublishableKey');
const hasDirectKeys = !!this.settings.stripeSecretKey && !!this.settings.stripePublishableKey;
const hasConnectKeys = !!this.settings.stripeConnectSecretKey && !!this.settings.stripeConnectPublishableKey;
if (stripeDirect) {
return hasDirectKeys;
@ -66,23 +66,23 @@ export default class MembersUtilsService extends Service {
}
get buttonIcon() {
return this.settings.get('portalButtonIcon') || this.defaultIconKeys[0];
return this.settings.portalButtonIcon || this.defaultIconKeys[0];
}
// Plan helpers ------------------------------------------------------------
get isFreeChecked() {
const allowedPlans = this.settings.get('portalPlans') || [];
return !!(this.settings.get('membersSignupAccess') === 'all' && allowedPlans.includes('free'));
const allowedPlans = this.settings.portalPlans || [];
return !!(this.settings.membersSignupAccess === 'all' && allowedPlans.includes('free'));
}
get isMonthlyChecked() {
const allowedPlans = this.settings.get('portalPlans') || [];
const allowedPlans = this.settings.portalPlans || [];
return !!(this.isStripeConfigured && allowedPlans.includes('monthly'));
}
get isYearlyChecked() {
const allowedPlans = this.settings.get('portalPlans') || [];
const allowedPlans = this.settings.portalPlans || [];
return !!(this.isStripeConfigured && allowedPlans.includes('yearly'));
}
@ -92,17 +92,17 @@ export default class MembersUtilsService extends Service {
let {
disableBackground = false,
page = 'signup',
button = this.settings.get('portalButton'),
button = this.settings.portalButton,
buttonIcon = this.buttonIcon,
isFreeChecked = this.isFreeChecked,
isMonthlyChecked = this.isMonthlyChecked,
isYearlyChecked = this.isYearlyChecked,
monthlyPrice,
yearlyPrice,
portalPlans = this.settings.get('portalPlans'),
portalPlans = this.settings.portalPlans,
portalTiers,
currency,
membersSignupAccess = this.settings.get('membersSignupAccess')
membersSignupAccess = this.settings.membersSignupAccess
} = overrides;
const tiers = this.store.peekAll('tier') || [];
@ -114,11 +114,11 @@ export default class MembersUtilsService extends Service {
const baseUrl = this.config.get('blogUrl');
const portalBase = '/#/portal/preview';
const settingsParam = new URLSearchParams();
const signupButtonText = this.settings.get('portalButtonSignupText') || '';
const signupButtonText = this.settings.portalButtonSignupText || '';
const allowSelfSignup = membersSignupAccess === 'all' && (!this.isStripeEnabled || isFreeChecked);
settingsParam.append('button', button);
settingsParam.append('name', this.settings.get('portalName'));
settingsParam.append('name', this.settings.portalName);
settingsParam.append('isFree', isFreeChecked);
settingsParam.append('isMonthly', isMonthlyChecked);
settingsParam.append('isYearly', isYearlyChecked);
@ -136,11 +136,11 @@ export default class MembersUtilsService extends Service {
settingsParam.append('portalProducts', encodeURIComponent(portalTiers));
}
if (this.settings.get('accentColor') === '' || this.settings.get('accentColor')) {
settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
if (this.settings.accentColor === '' || this.settings.accentColor) {
settingsParam.append('accentColor', encodeURIComponent(`${this.settings.accentColor}`));
}
if (this.settings.get('portalButtonStyle')) {
settingsParam.append('buttonStyle', encodeURIComponent(this.settings.get('portalButtonStyle')));
if (this.settings.portalButtonStyle) {
settingsParam.append('buttonStyle', encodeURIComponent(this.settings.portalButtonStyle));
}
if (monthlyPrice) {

View File

@ -1,5 +1,5 @@
import Service, {inject as service} from '@ember/service';
import {action, set} from '@ember/object';
import {action} from '@ember/object';
import {observes} from '@ember-decorators/object';
import {tracked} from '@glimmer/tracking';
@ -39,10 +39,7 @@ export default class NavigationService extends Service {
this.settings.expanded = {};
}
// set is still needed here because we're not tracking deep keys
// and Ember picks up that our templates are dependent on them and
// complains. TODO: can we avoid set?
set(this.settings.expanded, key, !this.settings.expanded[key]);
this.settings.expanded[key] = !this.settings.expanded[key];
return await this._saveNavigationSettings();
}

View File

@ -1,27 +1,28 @@
import Ember from 'ember';
import RSVP from 'rsvp';
import Service, {inject as service} from '@ember/service';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import classic from 'ember-classic-decorator';
import {get} from '@ember/object';
import {tracked} from '@glimmer/tracking';
// ember-cli-shims doesn't export _ProxyMixin
const {_ProxyMixin} = Ember;
@classic
export default class SettingsService extends Service.extend(_ProxyMixin, ValidationEngine) {
export default class SettingsService extends Service.extend(ValidationEngine) {
@service store;
// will be set to the single Settings model, it's a reference so any later
// changes to the settings object in the store will be reflected
content = null;
settingsModel = null;
validationType = 'setting';
_loadingPromise = null;
// this is an odd case where we only want to react to changes that we get
// back from the API rather than local updates
settledIcon = '';
@tracked settledIcon = '';
get hasDirtyAttributes() {
return this.settingsModel?.hasDirtyAttributes || false;
}
get mailgunIsConfigured() {
return this.mailgunApiKey && this.mailgunDomain && this.mailgunBaseUrl;
}
// the settings API endpoint is a little weird as it's singular and we have
// to pass in all types - if we ever fetch settings without all types then
@ -39,40 +40,56 @@ export default class SettingsService extends Service.extend(_ProxyMixin, Validat
return this._loadingPromise;
}
fetch() {
if (!this.content) {
async fetch() {
if (!this.settingsModel) {
return this.reload();
} else {
return RSVP.resolve(this);
return this;
}
}
reload() {
return this._loadSettings().then((settings) => {
this.set('content', settings);
this.set('settledIcon', get(settings, 'icon'));
return this;
async reload() {
const settingsModel = await this._loadSettings();
this.settingsModel = settingsModel;
this.settledIcon = settingsModel.icon;
settingsModel.eachAttribute((name) => {
if (!Object.prototype.hasOwnProperty.call(this, name)) {
Object.defineProperty(this, name, {
get() {
return this.settingsModel[name];
},
set(newValue) {
this.settingsModel[name] = newValue;
}
});
}
});
return this;
}
async save() {
let settings = this.content;
const {settingsModel} = this;
if (!settings) {
if (!settingsModel) {
return false;
}
await settings.save();
await settingsModel.save();
await this.validate();
this.set('settledIcon', settings.icon);
return settings;
this.settledIcon = settingsModel.icon;
return this;
}
rollbackAttributes() {
return this.content?.rollbackAttributes();
return this.settingsModel?.rollbackAttributes();
}
changedAttributes() {
return this.content?.changedAttributes();
return this.settingsModel?.changedAttributes();
}
}

View File

@ -193,11 +193,11 @@ export default class ThemeManagementService extends Service {
get previewData() {
const params = new URLSearchParams();
params.append('c', this.settings.get('accentColor') || '#ffffff');
params.append('d', this.settings.get('description'));
params.append('icon', this.settings.get('icon'));
params.append('logo', this.settings.get('logo'));
params.append('cover', this.settings.get('coverImage'));
params.append('c', this.settings.accentColor || '#ffffff');
params.append('d', this.settings.description);
params.append('icon', this.settings.icon);
params.append('logo', this.settings.logo);
params.append('cover', this.settings.coverImage);
params.append('custom', JSON.stringify(this.customThemeSettings.keyValueObject));

View File

@ -70,7 +70,7 @@ export default class UiService extends Service {
}
get adjustedAccentColor() {
const accentColor = Color(this.settings.get('accentColor'));
const accentColor = Color(this.settings.accentColor);
const backgroundColor = Color(this.backgroundColor);
// WCAG contrast. 1 = lowest contrast, 21 = highest contrast

View File

@ -113,8 +113,8 @@ export default class PublishOptions {
}
get emailDisabledInSettings() {
return get(this.settings, 'editorDefaultEmailRecipients') === 'disabled'
|| get(this.settings, 'membersSignupAccess') === 'none';
return this.settings.editorDefaultEmailRecipients === 'disabled'
|| this.settings.membersSignupAccess === 'none';
}
// publish type dropdown is not shown at all
@ -130,7 +130,7 @@ export default class PublishOptions {
}
get mailgunIsConfigured() {
return get(this.settings, 'mailgunIsConfigured')
return this.settings.mailgunIsConfigured
|| get(this.config, 'mailgunIsConfigured');
}
@ -168,8 +168,8 @@ export default class PublishOptions {
}
get defaultRecipientFilter() {
const recipients = this.settings.get('editorDefaultEmailRecipients');
const filter = this.settings.get('editorDefaultEmailRecipientsFilter');
const recipients = this.settings.editorDefaultEmailRecipients;
const filter = this.settings.editorDefaultEmailRecipientsFilter;
const usuallyNobody = recipients === 'filter' && filter === null;
@ -254,8 +254,8 @@ export default class PublishOptions {
// Set publish type to "Publish" but keep email recipients matching post visibility
// to avoid multiple clicks to turn on emailing
if (
this.settings.get('editorDefaultEmailRecipients') === 'filter' &&
this.settings.get('editorDefaultEmailRecipientsFilter') === null
this.settings.editorDefaultEmailRecipients === 'filter' &&
this.settings.editorDefaultEmailRecipientsFilter === null
) {
this.publishType = 'publish';
}
@ -382,7 +382,7 @@ export default class PublishOptions {
try {
if (this.limit.limiter && this.limit.limiter.isLimited('emails')) {
await this.limit.limiter.errorIfWouldGoOverLimit('emails');
} else if (get(this.settings, 'emailVerificationRequired')) {
} else if (this.settings.emailVerificationRequired) {
this.emailDisabledError = 'Email sending is temporarily disabled because your account is currently in review. You should have an email about this from us already, but you can also reach us any time at support@ghost.org.';
}
} catch (e) {

View File

@ -16,8 +16,8 @@ describe('Integration: Helper: gh-format-post-time', function () {
beforeEach(function () {
let settings = this.owner.lookup('service:settings');
settings.content = {};
settings.set('timezone', timezoneForTest);
settings.settingsModel = {};
settings.timezone = timezoneForTest;
});
afterEach(function () {

View File

@ -50,13 +50,13 @@ describe.skip('Unit: Controller: settings/design', function () {
NavItem.create({label: 'Third', url: ''})
]}));
// blank item won't get added because the last item is incomplete
expect(ctrl.get('settings.navigation.length')).to.equal(3);
expect(ctrl.settings.navigation.length).to.equal(3);
ctrl.get('save').perform().then(function passedValidation() {
assert(false, 'navigationItems weren\'t validated on save');
done();
}).catch(function failedValidation() {
let navItems = ctrl.get('settings.navigation');
let navItems = ctrl.settings.navigation;
expect(navItems[0].get('errors').toArray()).to.be.empty;
expect(navItems[1].get('errors.firstObject.attribute')).to.equal('label');
expect(navItems[2].get('errors.firstObject.attribute')).to.equal('url');
@ -74,13 +74,13 @@ describe.skip('Unit: Controller: settings/design', function () {
NavItem.create({label: '', url: ''})
]}));
expect(ctrl.get('settings.navigation.length')).to.equal(2);
expect(ctrl.settings.navigation.length).to.equal(2);
ctrl.get('save').perform().then(function passedValidation() {
assert(false, 'navigationItems weren\'t validated on save');
done();
}).catch(function failedValidation() {
let navItems = ctrl.get('settings.navigation');
let navItems = ctrl.settings.navigation;
expect(navItems[0].get('errors').toArray()).to.be.empty;
done();
});
@ -96,7 +96,7 @@ describe.skip('Unit: Controller: settings/design', function () {
]}));
});
expect(ctrl.get('settings.navigation.length')).to.equal(1);
expect(ctrl.settings.navigation.length).to.equal(1);
ctrl.set('newNavItem.label', 'New');
ctrl.set('newNavItem.url', '/new');
@ -105,10 +105,10 @@ describe.skip('Unit: Controller: settings/design', function () {
ctrl.send('addNavItem', ctrl.get('newNavItem'));
});
expect(ctrl.get('settings.navigation.length')).to.equal(2);
expect(ctrl.get('settings.navigation.lastObject.label')).to.equal('New');
expect(ctrl.get('settings.navigation.lastObject.url')).to.equal('/new');
expect(ctrl.get('settings.navigation.lastObject.isNew')).to.be.false;
expect(ctrl.settings.navigation.length).to.equal(2);
expect(ctrl.settings.navigation.lastObject.label).to.equal('New');
expect(ctrl.settings.navigation.lastObject.url).to.equal('/new');
expect(ctrl.settings.navigation.lastObject.isNew).to.be.false;
expect(ctrl.get('newNavItem.label')).to.be.empty;
expect(ctrl.get('newNavItem.url')).to.be.empty;
expect(ctrl.get('newNavItem.isNew')).to.be.true;
@ -121,9 +121,9 @@ describe.skip('Unit: Controller: settings/design', function () {
ctrl.set('settings', EmberObject.create({navigation: [
NavItem.create({label: '', url: '', last: true})
]}));
expect(ctrl.get('settings.navigation.length')).to.equal(1);
ctrl.send('addNavItem', ctrl.get('settings.navigation.lastObject'));
expect(ctrl.get('settings.navigation.length')).to.equal(1);
expect(ctrl.settings.navigation.length).to.equal(1);
ctrl.send('addNavItem', ctrl.settings.navigation.lastObject);
expect(ctrl.settings.navigation.length).to.equal(1);
});
});
@ -136,9 +136,9 @@ describe.skip('Unit: Controller: settings/design', function () {
run(() => {
ctrl.set('settings', EmberObject.create({navigation: navItems}));
expect(ctrl.get('settings.navigation').mapBy('label')).to.deep.equal(['First', 'Second']);
ctrl.send('deleteNavItem', ctrl.get('settings.navigation.firstObject'));
expect(ctrl.get('settings.navigation').mapBy('label')).to.deep.equal(['Second']);
expect(ctrl.settings.navigation.mapBy('label')).to.deep.equal(['First', 'Second']);
ctrl.send('deleteNavItem', ctrl.settings.navigation.firstObject);
expect(ctrl.settings.navigation.mapBy('label')).to.deep.equal(['Second']);
});
});
@ -151,9 +151,9 @@ describe.skip('Unit: Controller: settings/design', function () {
run(() => {
ctrl.set('settings', EmberObject.create({navigation: navItems}));
expect(ctrl.get('settings.navigation').mapBy('url')).to.deep.equal(['/first', '/second']);
ctrl.send('updateUrl', '/new', ctrl.get('settings.navigation.firstObject'));
expect(ctrl.get('settings.navigation').mapBy('url')).to.deep.equal(['/new', '/second']);
expect(ctrl.settings.navigation.mapBy('url')).to.deep.equal(['/first', '/second']);
ctrl.send('updateUrl', '/new', ctrl.settings.navigation.firstObject);
expect(ctrl.settings.navigation.mapBy('url')).to.deep.equal(['/new', '/second']);
});
});
});