0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Migrated route objects to native class syntax

no issue

- ran the `ember-native-class-codemod` codemod to convert just the route classes to native class syntax and performed some minor manual cleanup
  - modern Ember uses native classes rather than EmberObject-based objects, this brings us closer to normalizing our code style across the codebase
- skipped the Application route as that requires deeper testing with a replacement for the `ShortcutsRoute` mixin
This commit is contained in:
Kevin Ansfield 2022-01-17 09:34:55 +00:00
parent d09db70f43
commit 75abe76346
29 changed files with 249 additions and 246 deletions

View file

@ -1,10 +1,10 @@
import Route from '@ember/routing/route';
import {inject as service} from '@ember/service';
export default Route.extend({
session: service(),
export default class AuthenticatedRoute extends Route {
@service session;
beforeModel(transition) {
this.session.requireAuthentication(transition, 'signin');
}
});
}

View file

@ -1,13 +1,13 @@
import Route from '@ember/routing/route';
import {inject as service} from '@ember/service';
export default Route.extend({
config: service(),
export default class DesignsandboxRoute extends Route {
@service config;
beforeModel() {
this._super(...arguments);
if (!this.get('config.enableDeveloperExperiments')) {
super.beforeModel(...arguments);
if (!this.config.get('enableDeveloperExperiments')) {
return this.transitionTo('home');
}
}
});
}

View file

@ -1,9 +1,9 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {pluralize} from 'ember-inflector';
export default AuthenticatedRoute.extend({
export default class EditRoute extends AuthenticatedRoute {
beforeModel(transition) {
this._super(...arguments);
super.beforeModel(...arguments);
// if the transition is not new->edit, reset the post on the controller
// so that the editor view is cleared before showing the loading state
@ -12,7 +12,7 @@ export default AuthenticatedRoute.extend({
editor.set('post', null);
editor.reset();
}
},
}
model(params, transition) {
// eslint-disable-next-line camelcase
@ -29,13 +29,13 @@ export default AuthenticatedRoute.extend({
return this.store.query(modelName, query)
.then(records => records.get('firstObject'));
},
}
// the API will return a post even if the logged in user doesn't have
// permission to edit it (all posts are public) so we need to do our
// own permissions check and redirect if necessary
afterModel(post) {
this._super(...arguments);
super.afterModel(...arguments);
const user = this.session.user;
const returnRoute = pluralize(post.constructor.modelName);
@ -48,14 +48,14 @@ export default AuthenticatedRoute.extend({
if (user.isContributor && !post.isDraft) {
return this.replaceWith(returnRoute);
}
},
}
serialize(model) {
return {
type: model.constructor.modelName,
post_id: model.id
};
},
}
// there's no specific controller for this route, instead all editor
// handling is done on the editor route/controler
@ -63,4 +63,4 @@ export default AuthenticatedRoute.extend({
let editor = this.controllerFor('editor');
editor.setPost(post);
}
});
}

View file

@ -1,8 +1,8 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
export default AuthenticatedRoute.extend({
export default class IndexRoute extends AuthenticatedRoute {
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
this.replaceWith('editor.new', 'post');
}
});
}

View file

@ -1,6 +1,6 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
export default AuthenticatedRoute.extend({
export default class NewRoute extends AuthenticatedRoute {
model(params, transition) {
let {type: modelName} = params;
@ -10,18 +10,18 @@ export default AuthenticatedRoute.extend({
}
return this.store.createRecord(modelName, {authors: [this.session.user]});
},
}
// there's no specific controller for this route, instead all editor
// handling is done on the editor route/controler
setupController(controller, newPost) {
let editor = this.controllerFor('editor');
editor.setPost(newPost);
},
}
buildRouteInfoMetadata() {
return {
mainClasses: ['editor-new']
};
}
});
}

View file

@ -1,14 +1,14 @@
import Route from '@ember/routing/route';
export default Route.extend({
controllerName: 'error',
templateName: 'error',
export default class Error404Route extends Route {
controllerName = 'error';
templateName = 'error';
model() {
return {
status: 404
};
},
}
buildRouteInfoMetadata() {
return {
@ -16,4 +16,4 @@ export default Route.extend({
mainClasses: ['gh-main-white']
};
}
});
}

View file

@ -1,11 +1,11 @@
import PostsRoute from './posts';
export default PostsRoute.extend({
modelName: 'page',
export default class PagesRoute extends PostsRoute {
modelName = 'page';
buildRouteInfoMetadata() {
return {
titleToken: 'Pages'
};
}
});
}

View file

@ -1,27 +1,27 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {action} from '@ember/object';
import {assign} from '@ember/polyfills';
import {isBlank} from '@ember/utils';
import {inject as service} from '@ember/service';
export default AuthenticatedRoute.extend({
infinity: service(),
router: service(),
export default class PostsRoute extends AuthenticatedRoute {
@service infinity;
@service router;
queryParams: {
queryParams = {
type: {refreshModel: true},
visibility: {refreshModel: true},
access: {refreshModel: true},
author: {refreshModel: true},
tag: {refreshModel: true},
order: {refreshModel: true}
},
};
modelName: 'post',
modelName = 'post';
perPage = 30;
perPage: 30,
init() {
this._super(...arguments);
constructor() {
super(...arguments);
// if we're already on this route and we're transiting _to_ this route
// then the filters are being changed and we shouldn't create a new
@ -35,7 +35,7 @@ export default AuthenticatedRoute.extend({
}
}
});
},
}
model(params) {
const user = this.session.user;
@ -76,11 +76,11 @@ export default AuthenticatedRoute.extend({
let paginationSettings = assign({perPage, startingPage: 1}, paginationParams, queryParams);
return this.infinity.model(this.modelName, paginationSettings);
},
}
// trigger a background load of all tags, authors, and snipps for use in filter dropdowns and card menu
setupController(controller) {
this._super(...arguments);
super.setupController(...arguments);
if (!controller._hasLoadedTags) {
this.store.query('tag', {limit: 'all'}).then(() => {
@ -99,25 +99,24 @@ export default AuthenticatedRoute.extend({
controller._hasLoadedSnippets = true;
});
}
},
}
actions: {
queryParamsDidChange() {
// scroll back to the top
let contentList = document.querySelector('.content-list');
if (contentList) {
contentList.scrollTop = 0;
}
this._super(...arguments);
@action
queryParamsDidChange() {
// scroll back to the top
let contentList = document.querySelector('.content-list');
if (contentList) {
contentList.scrollTop = 0;
}
},
super.actions.queryParamsDidChange.call(this, ...arguments);
}
buildRouteInfoMetadata() {
return {
titleToken: 'Posts'
};
},
}
_getTypeFilters(type) {
let status = '[draft,scheduled,published,sent]';
@ -140,7 +139,7 @@ export default AuthenticatedRoute.extend({
return {
status
};
},
}
_filterString(filter) {
return Object.keys(filter).map((key) => {
@ -151,4 +150,4 @@ export default AuthenticatedRoute.extend({
}
}).compact().join('+');
}
});
}

View file

@ -1,18 +1,18 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
// TODO: rename billing route and service to /pro
export default AuthenticatedRoute.extend({
billing: service(),
session: service(),
config: service(),
export default class ProRoute extends AuthenticatedRoute {
@service billing;
@service session;
@service config;
queryParams: {
queryParams = {
action: {refreshModel: true}
},
};
beforeModel(transition) {
this._super(...arguments);
super.beforeModel(...arguments);
// allow non-owner users to access the BMA when we're in a force upgrade state
if (!this.session.user.isOwnerOnly && !this.config.get('hostSettings.forceUpgrade')) {
@ -20,7 +20,7 @@ export default AuthenticatedRoute.extend({
}
this.billing.set('previousTransition', transition);
},
}
model(params) {
if (params.action) {
@ -28,31 +28,30 @@ export default AuthenticatedRoute.extend({
}
this.billing.toggleProWindow(true);
},
}
actions: {
willTransition(transition) {
let isBillingTransition = false;
@action
willTransition(transition) {
let isBillingTransition = false;
if (transition) {
let destinationUrl = (typeof transition.to === 'string')
? transition.to
: (transition.intent
? transition.intent.url
: '');
if (transition) {
let destinationUrl = (typeof transition.to === 'string')
? transition.to
: (transition.intent
? transition.intent.url
: '');
if (destinationUrl?.includes('/pro')) {
isBillingTransition = true;
}
if (destinationUrl?.includes('/pro')) {
isBillingTransition = true;
}
this.billing.toggleProWindow(isBillingTransition);
}
},
this.billing.toggleProWindow(isBillingTransition);
}
buildRouteInfoMetadata() {
return {
titleToken: 'Ghost(Pro)'
};
}
});
}

View file

@ -1,25 +1,25 @@
import UnauthenticatedRoute from 'ghost-admin/routes/unauthenticated';
import {inject as service} from '@ember/service';
export default UnauthenticatedRoute.extend({
notifications: service(),
session: service(),
export default class ResetRoute extends UnauthenticatedRoute {
@service notifications;
@service session;
beforeModel() {
if (this.get('session.isAuthenticated')) {
if (this.session.isAuthenticated) {
this.notifications.showAlert('You can\'t reset your password while you\'re signed in.', {type: 'warn', delayed: true, key: 'password.reset.signed-in'});
}
this._super(...arguments);
},
super.beforeModel(...arguments);
}
setupController(controller, params) {
controller.token = params.token;
},
}
// Clear out any sensitive information
deactivate() {
this._super(...arguments);
super.deactivate(...arguments);
this.controller.clearData();
}
});
}

View file

@ -1,11 +1,11 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {inject as service} from '@ember/service';
export default AuthenticatedRoute.extend({
session: service(),
export default class SettingsRoute extends AuthenticatedRoute {
@service session;
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
const user = this.session.user;
@ -13,4 +13,4 @@ export default AuthenticatedRoute.extend({
return this.transitionTo('settings.staff.user', user);
}
}
});
}

View file

@ -1,14 +1,14 @@
import AdminRoute from 'ghost-admin/routes/admin';
export default AdminRoute.extend({
export default class EditRoute extends AdminRoute {
model(params) {
let integration = this.modelFor('settings.integration');
let webhook = integration.webhooks.findBy('id', params.webhook_id);
return webhook;
},
}
deactivate() {
this._super(...arguments);
super.deactivate(...arguments);
this.controller.reset();
}
});
}

View file

@ -1,13 +1,13 @@
import AdminRoute from 'ghost-admin/routes/admin';
export default AdminRoute.extend({
export default class NewRoute extends AdminRoute {
model() {
let integration = this.modelFor('settings.integration');
return this.store.createRecord('webhook', {integration});
},
}
deactivate() {
this._super(...arguments);
super.deactivate(...arguments);
this.controller.webhook.rollbackAttributes();
}
});
}

View file

@ -1,18 +1,18 @@
import AdminRoute from 'ghost-admin/routes/admin';
import {inject as service} from '@ember/service';
export default AdminRoute.extend({
settings: service(),
export default class IntegrationsRoute extends AdminRoute {
@service settings;
setupController(controller) {
// kick off the background fetch of integrations so that we can
// show the screen immediately
controller.fetchIntegrations.perform();
},
}
buildRouteInfoMetadata() {
return {
titleToken: 'Settings - Integrations'
};
}
});
}

View file

@ -1,27 +1,27 @@
import AdminRoute from 'ghost-admin/routes/admin';
import {inject as service} from '@ember/service';
export default AdminRoute.extend({
router: service(),
config: service(),
export default class ZapierRoute extends AdminRoute {
@service router;
@service config;
init() {
this._super(...arguments);
constructor() {
super(...arguments);
this.router.on('routeWillChange', () => {
if (this.controller) {
this.controller.set('selectedApiKey', null);
this.controller.set('isApiKeyRegenerated', false);
}
});
},
}
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
if (this.config.get('hostSettings.limits.customIntegrations.disabled')) {
return this.transitionTo('settings.integrations');
}
},
}
model(params, transition) {
// use the integrations controller to fetch all integrations and pick
@ -30,11 +30,11 @@ export default AdminRoute.extend({
return this
.controllerFor('settings.integrations')
.integrationModelHook('slug', 'zapier', this, transition);
},
}
buildRouteInfoMetadata() {
return {
titleToken: 'Zapier'
};
}
});
}

View file

@ -1,23 +1,23 @@
import AdminRoute from 'ghost-admin/routes/admin';
import {inject as service} from '@ember/service';
export default AdminRoute.extend({
settings: service(),
notifications: service(),
export default class LabsRoute extends AdminRoute {
@service settings;
@service notifications;
model() {
return this.settings.reload();
},
}
resetController(controller, isExiting) {
if (isExiting) {
controller.reset();
}
},
}
buildRouteInfoMetadata() {
return {
titleToken: 'Settings - Labs'
};
}
});
}

View file

@ -1,12 +1,13 @@
import AdminRoute from 'ghost-admin/routes/admin';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
export default AdminRoute.extend({
notifications: service(),
settings: service(),
export default class MembersEmailRoute extends AdminRoute {
@service notifications;
@service settings;
beforeModel(transition) {
this._super(...arguments);
super.beforeModel(...arguments);
if (transition.to.queryParams?.fromAddressUpdate === 'success') {
this.notifications.showAlert(
@ -19,25 +20,24 @@ export default AdminRoute.extend({
{type: 'success', key: 'members.settings.support-address.updated'}
);
}
},
}
model() {
return this.settings.reload();
},
}
setupController(controller) {
controller.resetEmailAddresses();
},
}
actions: {
willTransition(transition) {
return this.controller.leaveRoute(transition);
}
},
@action
willTransition(transition) {
return this.controller.leaveRoute(transition);
}
buildRouteInfoMetadata() {
return {
titleToken: 'Settings - Members'
};
}
});
}

View file

@ -1,28 +1,28 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
export default AuthenticatedRoute.extend({
infinity: service(),
session: service(),
export default class IndexRoute extends AuthenticatedRoute {
@service infinity;
@service session;
model() {
return this.session.user;
},
}
setupController(controller) {
this._super(...arguments);
super.setupController(...arguments);
controller.backgroundUpdate.perform();
},
}
actions: {
reload() {
this.controller.backgroundUpdate.perform();
}
},
@action
reload() {
this.controller.backgroundUpdate.perform();
}
buildRouteInfoMetadata() {
return {
titleToken: 'Staff'
};
}
});
}

View file

@ -1,13 +1,14 @@
import {action} from '@ember/object';
/* eslint-disable camelcase */
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
export default AuthenticatedRoute.extend({
export default class UserRoute extends AuthenticatedRoute {
model(params) {
return this.store.queryRecord('user', {slug: params.user_slug, include: 'count.posts'});
},
}
afterModel(user) {
this._super(...arguments);
super.afterModel(...arguments);
const currentUser = this.session.user;
@ -27,45 +28,46 @@ export default AuthenticatedRoute.extend({
this.controller.set('personalTokenRegenerated', false);
});
}
},
}
serialize(model) {
return {user_slug: model.get('slug')};
},
}
actions: {
didTransition() {
this.modelFor('settings.staff.user').get('errors').clear();
},
@action
didTransition() {
this.modelFor('settings.staff.user').get('errors').clear();
}
save() {
this.get('controller.save').perform();
},
@action
save() {
this.controller.save.perform();
}
willTransition(transition) {
let controller = this.controller;
let user = controller.user;
let dirtyAttributes = controller.dirtyAttributes;
let modelIsDirty = user.get('hasDirtyAttributes');
@action
willTransition(transition) {
let controller = this.controller;
let user = controller.user;
let dirtyAttributes = controller.dirtyAttributes;
let modelIsDirty = user.get('hasDirtyAttributes');
// always reset the password properties on the user model when leaving
if (user) {
user.set('password', '');
user.set('newPassword', '');
user.set('ne2Password', '');
}
if (modelIsDirty || dirtyAttributes) {
transition.abort();
controller.send('toggleLeaveSettingsModal', transition);
return;
}
// always reset the password properties on the user model when leaving
if (user) {
user.set('password', '');
user.set('newPassword', '');
user.set('ne2Password', '');
}
},
if (modelIsDirty || dirtyAttributes) {
transition.abort();
controller.send('toggleLeaveSettingsModal', transition);
return;
}
}
buildRouteInfoMetadata() {
return {
titleToken: 'Staff - User'
};
}
});
}

View file

@ -1,22 +1,22 @@
import Route from '@ember/routing/route';
import {inject as service} from '@ember/service';
export default Route.extend({
ghostPaths: service(),
session: service(),
ajax: service(),
config: service(),
export default class SetupRoute extends Route {
@service ghostPaths;
@service session;
@service ajax;
@service config;
// use the beforeModel hook to check to see whether or not setup has been
// previously completed. If it has, stop the transition into the setup page.
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
if (this.get('session.isAuthenticated')) {
if (this.session.isAuthenticated) {
return this.transitionTo('home');
}
let authUrl = this.get('ghostPaths.url').api('authentication', 'setup');
let authUrl = this.ghostPaths.url.api('authentication', 'setup');
// check the state of the setup process via the API
return this.ajax.request(authUrl)
@ -40,12 +40,12 @@ export default Route.extend({
}
}
});
},
}
deactivate() {
this._super(...arguments);
super.deactivate(...arguments);
this.controllerFor('setup/two').set('password', '');
},
}
buildRouteInfoMetadata() {
return {
@ -54,4 +54,4 @@ export default Route.extend({
mainClasses: ['gh-main-white']
};
}
});
}

View file

@ -1,8 +1,8 @@
import Route from '@ember/routing/route';
export default Route.extend({
export default class IndexRoute extends Route {
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
this.transitionTo('setup.one');
}
});
}

View file

@ -1,10 +1,10 @@
import Route from '@ember/routing/route';
export default Route.extend({
export default class ThreeRoute extends Route {
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
if (!this.controllerFor('setup.two').get('blogCreated')) {
this.transitionTo('setup.two');
}
}
});
}

View file

@ -14,24 +14,24 @@ const defaultModel = function defaultModel() {
});
};
export default UnauthenticatedRoute.extend({
export default class SigninRoute extends UnauthenticatedRoute {
model() {
return defaultModel();
},
}
// the deactivate hook is called after a route has been exited.
deactivate() {
let controller = this.controllerFor('signin');
this._super(...arguments);
super.deactivate(...arguments);
// clear the properties that hold the credentials when we're no longer on the signin screen
controller.set('signin', defaultModel());
},
}
buildRouteInfoMetadata() {
return Object.assign(this._super(), {
return Object.assign(super.buildRouteInfoMetadata(), {
titleToken: 'Sign In'
});
}
});
}

View file

@ -1,17 +1,17 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {inject as service} from '@ember/service';
export default AuthenticatedRoute.extend({
notifications: service(),
export default class SignoutRoute extends AuthenticatedRoute {
@service notifications;
afterModel(/*model, transition*/) {
afterModel/*model, transition*/() {
this.notifications.clearAll();
this.session.invalidate();
},
}
buildRouteInfoMetadata() {
return {
titleToken: 'Sign Out'
};
}
});
}

View file

@ -1,3 +1,4 @@
import {inject as service} from '@ember/service';
// TODO: remove usage of Ember Data's private `Errors` class when refactoring validations
// eslint-disable-next-line
import DS from 'ember-data';
@ -5,30 +6,32 @@ import EmberObject from '@ember/object';
import RSVP from 'rsvp';
import UnauthenticatedRoute from 'ghost-admin/routes/unauthenticated';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import {inject as service} from '@ember/service';
import classic from 'ember-classic-decorator';
const {Promise} = RSVP;
const {Errors} = DS;
export default UnauthenticatedRoute.extend({
ghostPaths: service(),
notifications: service(),
session: service(),
ajax: service(),
config: service(),
export default class SignupRoute extends UnauthenticatedRoute {
@service ghostPaths;
@service notifications;
@service session;
@service ajax;
@service config;
beforeModel() {
if (this.get('session.isAuthenticated')) {
if (this.session.isAuthenticated) {
this.notifications.showAlert('You need to sign out to register as a new user.', {type: 'warn', delayed: true, key: 'signup.create.already-authenticated'});
}
this._super(...arguments);
},
super.beforeModel(...arguments);
}
model(params) {
let SignupDetails = EmberObject.extend(ValidationEngine, {
validationType: 'signup'
});
@classic
class SignupDetails extends EmberObject.extend(ValidationEngine) {
validationType = 'signup';
}
let signupDetails = SignupDetails.create();
let re = /^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-]{2}|[A-Za-z0-9_-]{3})?$/;
let email,
@ -73,12 +76,12 @@ export default UnauthenticatedRoute.extend({
resolve(signupDetails);
});
});
},
}
deactivate() {
this._super(...arguments);
super.deactivate(...arguments);
// clear the properties that hold the sensitive data from the controller
this.controllerFor('signup').get('signupDetails').setProperties({email: '', password: '', token: ''});
}
});
}

View file

@ -1,20 +1,20 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import {inject as service} from '@ember/service';
export default AuthenticatedRoute.extend({
config: service(),
settings: service(),
ui: service(),
export default class SiteRoute extends AuthenticatedRoute {
@service config;
@service settings;
@service ui;
_hasLoggedIn: false,
_hasLoggedIn = false;
model() {
return (new Date()).valueOf();
},
}
buildRouteInfoMetadata() {
return {
titleToken: 'Site'
};
}
});
}

View file

@ -1,6 +1,6 @@
import TagRoute from '../tag';
export default TagRoute.extend({
controllerName: 'tag',
templateName: 'tag'
});
export default class NewRoute extends TagRoute {
controllerName = 'tag';
templateName = 'tag';
}

View file

@ -1,21 +1,21 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
export default AuthenticatedRoute.extend({
queryParams: {
export default class TagsRoute extends AuthenticatedRoute {
queryParams = {
type: {
refreshModel: true,
replace: true
}
},
};
// authors aren't allowed to manage tags
beforeModel() {
this._super(...arguments);
super.beforeModel(...arguments);
if (this.session.user.isAuthorOrContributor) {
return this.transitionTo('home');
}
},
}
// set model to a live array so all tags are shown and created/deleted tags
// are automatically added/removed. Also load all tags in the background,
@ -28,11 +28,11 @@ export default AuthenticatedRoute.extend({
} else {
return tags;
}
},
}
buildRouteInfoMetadata() {
return {
titleToken: 'Tags'
};
}
});
}

View file

@ -1,9 +1,9 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
export default AuthenticatedRoute.extend({
export default class WhatsnewRoute extends AuthenticatedRoute {
buildRouteInfoMetadata() {
return {
titleToken: `What's new?`
};
}
});
}