Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
🎨 Added auto-login to private site when viewing site preview in admin
Browse files Browse the repository at this point in the history
closes TryGhost/Ghost#10995

- when first loading the site preview, if private mode is enabled submit the login form in the background to get the cookie before loading the iframe
- refactors post-authentication preloading to ensure it occurs before post-authentication route hooks are called
- adds `showSuccess` attribute to `<GhTaskButton>` so that when set to `false` it can stay in the running state after "success" to avoid state change flashes whilst waiting for a transition
  • Loading branch information
kevinansfield committed Aug 8, 2019
1 parent 85c11b6 commit 6a97914
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 44 deletions.
18 changes: 17 additions & 1 deletion app/authenticators/cookie.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import {inject as service} from '@ember/service';

export default Authenticator.extend({
ajax: service(),
config: service(),
feature: service(),
ghostPaths: service(),
settings: service(),
tour: service(),

sessionEndpoint: computed('ghostPaths.apiRoot', function () {
return `${this.ghostPaths.apiRoot}/session`;
Expand All @@ -24,7 +28,19 @@ export default Authenticator.extend({
dataType: 'text'
};

return this.ajax.post(this.sessionEndpoint, options);
return this.ajax.post(this.sessionEndpoint, options).then((authResult) => {
// TODO: remove duplication with application.afterModel
let preloadPromises = [
this.config.fetchAuthenticated(),
this.feature.fetch(),
this.settings.fetch(),
this.tour.fetchViewed()
];

return RSVP.all(preloadPromises).then(() => {
return authResult;
});
});
},

invalidate() {
Expand Down
14 changes: 12 additions & 2 deletions app/components/gh-task-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const GhTaskButton = Component.extend({
buttonText: 'Save',
idleClass: '',
runningClass: '',
showSuccess: true, // set to false if you want the spinner to show until a transition occurs
successText: 'Saved',
successClass: 'gh-btn-green',
failureText: 'Retry',
Expand All @@ -40,7 +41,6 @@ const GhTaskButton = Component.extend({
// Allowed actions
action: () => {},

isRunning: reads('task.last.isRunning'),
runningText: reads('buttonText'),

// hasRun is needed so that a newly rendered button does not show the last
Expand All @@ -53,12 +53,22 @@ const GhTaskButton = Component.extend({
return this.isIdle ? this.idleClass : '';
}),

isRunning: computed('task.last.isRunning', 'hasRun', 'showSuccess', function () {
let isRunning = this.get('task.last.isRunning');

if (this.hasRun && this.get('task.last.value') && !this.showSuccess) {
isRunning = true;
}

return isRunning;
}),

isRunningClass: computed('isRunning', function () {
return this.isRunning ? (this.runningClass || this.idleClass) : '';
}),

isSuccess: computed('hasRun', 'isRunning', 'task.last.value', function () {
if (!this.hasRun || this.isRunning) {
if (!this.hasRun || this.isRunning || !this.showSuccess) {
return false;
}

Expand Down
21 changes: 7 additions & 14 deletions app/controllers/signin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import $ from 'jquery';
import Controller, {inject as controller} from '@ember/controller';
import RSVP from 'rsvp';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import {alias} from '@ember/object/computed';
import {isArray as isEmberArray} from '@ember/array';
Expand Down Expand Up @@ -34,23 +33,15 @@ export default Controller.extend(ValidationEngine, {

actions: {
authenticate() {
this.validateAndAuthenticate.perform();
return this.validateAndAuthenticate.perform();
}
},

authenticate: task(function* (authStrategy, authentication) {
try {
let authResult = yield this.session
.authenticate(authStrategy, ...authentication);
let promises = [];

promises.pushObject(this.settings.fetch());
promises.pushObject(this.config.fetchAuthenticated());

// fetch settings and private config for synchronous access
yield RSVP.all(promises);

return authResult;
return yield this.session
.authenticate(authStrategy, ...authentication)
.then(() => true); // ensure task button transitions to "success" state
} catch (error) {
if (isVersionMismatchError(error)) {
return this.notifications.showAPIError(error);
Expand All @@ -72,6 +63,7 @@ export default Controller.extend(ValidationEngine, {
this.get('signin.errors').add('password', '');
}
} else {
console.error(error);
// Connection errors don't return proper status message, only req.body
this.notifications.showAlert(
'There was a problem on the server.',
Expand All @@ -96,7 +88,8 @@ export default Controller.extend(ValidationEngine, {
try {
yield this.validate({property: 'signin'});
return yield this.authenticate
.perform(authStrategy, [signin.get('identification'), signin.get('password')]);
.perform(authStrategy, [signin.get('identification'), signin.get('password')])
.then(() => true);
} catch (error) {
this.set('flowErrors', 'Please fill out the form to sign in.');
}
Expand Down
13 changes: 4 additions & 9 deletions app/routes/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,13 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
this.set('appLoadTransition', transition);
transition.send('loadServerNotifications');

let configPromise = this.config.fetchAuthenticated();
let featurePromise = this.feature.fetch();
let settingsPromise = this.settings.fetch();
let tourPromise = this.tour.fetchViewed();

// return the feature/settings load promises so that we block until
// they are loaded to enable synchronous access everywhere
return RSVP.all([
configPromise,
featurePromise,
settingsPromise,
tourPromise
this.config.fetchAuthenticated(),
this.feature.fetch(),
this.settings.fetch(),
this.tour.fetchViewed()
]).then((results) => {
this._appLoaded = true;
return results;
Expand Down
26 changes: 20 additions & 6 deletions app/routes/site.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import fetch from 'fetch';
import {inject as service} from '@ember/service';

export default AuthenticatedRoute.extend({

config: service(),
settings: service(),
ui: service(),

_hasLoggedIn: false,

model() {
return (new Date()).valueOf();
},

activate() {
this._super(...arguments);
},
afterModel() {
if (this.settings.get('isPrivate') && !this._hasLoggedIn) {
let privateLoginUrl = `${this.config.get('blogUrl')}/private/?r=%2F`;

deactivate() {
this._super(...arguments);
return fetch(privateLoginUrl, {
method: 'POST',
mode: 'cors',
redirect: 'manual',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `password=${this.settings.get('password')}`
}).then(() => {
this._hasLoggedIn = true;
});
}
},

buildRouteInfoMetadata() {
Expand Down
13 changes: 1 addition & 12 deletions app/services/session.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import RSVP from 'rsvp';
import SessionService from 'ember-simple-auth/services/session';
import {computed} from '@ember/object';
import {inject as service} from '@ember/service';

export default SessionService.extend({
feature: service(),
dataStore: service('store'), // SessionService.store already exists
tour: service(),

user: computed(function () {
return this.dataStore.queryRecord('user', {id: 'me'});
Expand All @@ -16,14 +13,6 @@ export default SessionService.extend({
// ensure any cached this.user value is removed and re-fetched
this.notifyPropertyChange('user');

return this._super(...arguments).then((authResult) => {
// TODO: remove duplication with application.afterModel
let preloadPromises = [
this.feature.fetch(),
this.tour.fetchViewed()
];

return RSVP.all(preloadPromises).then(() => authResult);
});
return this._super(...arguments);
}
});
1 change: 1 addition & 0 deletions app/templates/signin.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

{{gh-task-button "Sign in"
task=validateAndAuthenticate
showSuccess=false
class="login gh-btn gh-btn-blue gh-btn-block gh-btn-icon"
type="submit"
tabindex="3"}}
Expand Down

0 comments on commit 6a97914

Please sign in to comment.