mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 22:02:11 +03:00
c3b49b45cf
no issue - adds `settings` service that acts as a proxy to the singular settings model with methods to fetch and reload, also prevents accidentally loading only some settings types which has caused problems in the past - updates app boot, signin, and signup processes to fetch settings ensuring that any part of the app can grab settings synchronously if needed - removes `timeZone` service, it's no longer needed as we can grab `settings.activeTimezone` directly - replaces all store queries for the settings model with appropriate `settings` methods - refactors `apps/*` routes/controllers, they had become a little convoluted with the way they were dealing with settings and the new service helped to clean that up
260 lines
8.9 KiB
JavaScript
260 lines
8.9 KiB
JavaScript
import Route from 'ember-route';
|
|
import {htmlSafe} from 'ember-string';
|
|
import injectService from 'ember-service/inject';
|
|
import run from 'ember-runloop';
|
|
import {isEmberArray} from 'ember-array/utils';
|
|
import observer from 'ember-metal/observer';
|
|
import $ from 'jquery';
|
|
import {isUnauthorizedError} from 'ember-ajax/errors';
|
|
import AuthConfiguration from 'ember-simple-auth/configuration';
|
|
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
|
|
import ShortcutsRoute from 'ghost-admin/mixins/shortcuts-route';
|
|
import ctrlOrCmd from 'ghost-admin/utils/ctrl-or-cmd';
|
|
import windowProxy from 'ghost-admin/utils/window-proxy';
|
|
import RSVP from 'rsvp';
|
|
|
|
function K() {
|
|
return this;
|
|
}
|
|
|
|
let shortcuts = {};
|
|
|
|
shortcuts.esc = {action: 'closeMenus', scope: 'all'};
|
|
shortcuts[`${ctrlOrCmd}+s`] = {action: 'save', scope: 'all'};
|
|
|
|
export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
|
shortcuts,
|
|
|
|
routeAfterAuthentication: 'posts',
|
|
|
|
config: injectService(),
|
|
feature: injectService(),
|
|
dropdown: injectService(),
|
|
lazyLoader: injectService(),
|
|
notifications: injectService(),
|
|
settings: injectService(),
|
|
upgradeNotification: injectService(),
|
|
|
|
beforeModel() {
|
|
return this.get('config').fetch();
|
|
},
|
|
|
|
afterModel(model, transition) {
|
|
this._super(...arguments);
|
|
|
|
if (this.get('session.isAuthenticated')) {
|
|
this.set('appLoadTransition', transition);
|
|
transition.send('loadServerNotifications');
|
|
transition.send('checkForOutdatedDesktopApp');
|
|
|
|
// trigger a background refresh of the access token to enable
|
|
// "infinite" sessions. We also trigger a logout if the refresh
|
|
// token is invalid to prevent attackers with only the access token
|
|
// from loading the admin
|
|
let session = this.get('session.session');
|
|
let authenticator = session._lookupAuthenticator(session.authenticator);
|
|
if (authenticator && authenticator.onOnline) {
|
|
authenticator.onOnline();
|
|
}
|
|
|
|
let featurePromise = this.get('feature').fetch().then(() => {
|
|
if (this.get('feature.nightShift')) {
|
|
return this._setAdminTheme();
|
|
}
|
|
});
|
|
|
|
let settingsPromise = this.get('settings').fetch();
|
|
|
|
// return the feature/settings load promises so that we block until
|
|
// they are loaded to enable synchronous access everywhere
|
|
return RSVP.all([
|
|
featurePromise,
|
|
settingsPromise
|
|
]);
|
|
}
|
|
},
|
|
|
|
title(tokens) {
|
|
return `${tokens.join(' - ')} - ${this.get('config.blogTitle')}`;
|
|
},
|
|
|
|
sessionAuthenticated() {
|
|
if (this.get('session.skipAuthSuccessHandler')) {
|
|
return;
|
|
}
|
|
|
|
// standard ESA post-sign-in redirect
|
|
this._super(...arguments);
|
|
|
|
// trigger post-sign-in background behaviour
|
|
this.get('session.user').then((user) => {
|
|
this.send('signedIn', user);
|
|
});
|
|
},
|
|
|
|
sessionInvalidated() {
|
|
let transition = this.get('appLoadTransition');
|
|
|
|
if (transition) {
|
|
transition.send('authorizationFailed');
|
|
} else {
|
|
run.scheduleOnce('routerTransitions', this, function () {
|
|
this.send('authorizationFailed');
|
|
});
|
|
}
|
|
},
|
|
|
|
_nightShift: observer('feature.nightShift', function () {
|
|
this._setAdminTheme();
|
|
}),
|
|
|
|
_setAdminTheme() {
|
|
let nightShift = this.get('feature.nightShift');
|
|
|
|
return this.get('lazyLoader').loadStyle('dark', 'assets/ghost-dark.css', true).then(() => {
|
|
$('link[title=dark]').prop('disabled', !nightShift);
|
|
$('link[title=light]').prop('disabled', nightShift);
|
|
});
|
|
},
|
|
|
|
actions: {
|
|
openMobileMenu() {
|
|
this.controller.set('showMobileMenu', true);
|
|
},
|
|
|
|
openSettingsMenu() {
|
|
this.controller.set('showSettingsMenu', true);
|
|
},
|
|
|
|
closeMenus() {
|
|
this.get('dropdown').closeDropdowns();
|
|
this.controller.setProperties({
|
|
showSettingsMenu: false,
|
|
showMobileMenu: false
|
|
});
|
|
},
|
|
|
|
didTransition() {
|
|
this.set('appLoadTransition', null);
|
|
this.send('closeMenus');
|
|
},
|
|
|
|
signedIn() {
|
|
this.get('notifications').clearAll();
|
|
this.send('loadServerNotifications', true);
|
|
|
|
if (this.get('feature.nightShift')) {
|
|
this._setAdminTheme();
|
|
}
|
|
},
|
|
|
|
invalidateSession() {
|
|
this.get('session').invalidate().catch((error) => {
|
|
this.get('notifications').showAlert(error.message, {type: 'error', key: 'session.invalidate.failed'});
|
|
});
|
|
},
|
|
|
|
authorizationFailed() {
|
|
windowProxy.replaceLocation(AuthConfiguration.baseURL);
|
|
},
|
|
|
|
loadServerNotifications(isDelayed) {
|
|
if (this.get('session.isAuthenticated')) {
|
|
this.get('session.user').then((user) => {
|
|
if (!user.get('isAuthor') && !user.get('isEditor')) {
|
|
this.store.findAll('notification', {reload: true}).then((serverNotifications) => {
|
|
serverNotifications.forEach((notification) => {
|
|
if (notification.get('type') === 'upgrade') {
|
|
this.get('upgradeNotification').set('content', notification.get('message'));
|
|
} else {
|
|
this.get('notifications').handleNotification(notification, isDelayed);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
checkForOutdatedDesktopApp() {
|
|
// Check if the user is running an older version of Ghost Desktop
|
|
// that needs to be manually updated
|
|
// (yes, the desktop team is deeply ashamed of these lines 😢)
|
|
let ua = navigator && navigator.userAgent ? navigator.userAgent : null;
|
|
|
|
if (ua && ua.includes && ua.includes('ghost-desktop')) {
|
|
let updateCheck = /ghost-desktop\/0\.((5\.0)|((4|2)\.0)|((3\.)(0|1)))/;
|
|
let link = '<a href="https://dev.ghost.org/ghost-desktop-manual-update" target="_blank">click here</a>';
|
|
let msg = `Your version of Ghost Desktop needs to be manually updated. Please ${link} to get started.`;
|
|
|
|
if (updateCheck.test(ua)) {
|
|
this.get('notifications').showAlert(htmlSafe(msg), {
|
|
type: 'warn',
|
|
key: 'desktop.manual.upgrade'
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
toggleMarkdownHelpModal() {
|
|
this.get('controller').toggleProperty('showMarkdownHelpModal');
|
|
},
|
|
|
|
// noop default for unhandled save (used from shortcuts)
|
|
save: K,
|
|
|
|
error(error, transition) {
|
|
// unauthoirized errors are already handled in the ajax service
|
|
if (isUnauthorizedError(error)) {
|
|
return false;
|
|
}
|
|
|
|
if (error && isEmberArray(error.errors)) {
|
|
switch (error.errors[0].errorType) {
|
|
case 'NotFoundError': {
|
|
if (transition) {
|
|
transition.abort();
|
|
}
|
|
|
|
let routeInfo = transition.handlerInfos[transition.handlerInfos.length - 1];
|
|
let router = this.get('router');
|
|
let params = [];
|
|
|
|
for (let key of Object.keys(routeInfo.params)) {
|
|
params.push(routeInfo.params[key]);
|
|
}
|
|
|
|
return this.transitionTo('error404', router.generate(routeInfo.name, ...params).replace('/ghost/', '').replace(/^\//g, ''));
|
|
}
|
|
case 'VersionMismatchError': {
|
|
if (transition) {
|
|
transition.abort();
|
|
}
|
|
|
|
this.get('upgradeStatus').requireUpgrade();
|
|
return false;
|
|
}
|
|
case 'Maintenance': {
|
|
if (transition) {
|
|
transition.abort();
|
|
}
|
|
|
|
this.get('upgradeStatus').maintenanceAlert();
|
|
return false;
|
|
}
|
|
default: {
|
|
this.get('notifications').showAPIError(error);
|
|
// don't show the 500 page if we weren't navigating
|
|
if (!transition) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// fallback to 500 error page
|
|
return true;
|
|
}
|
|
}
|
|
});
|