You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gristlabs_grist-core/app/client/components/Login.js

130 lines
4.3 KiB

/* global window */
// External dependencies
const Promise = require('bluebird');
const ko = require('knockout');
// Grist client libs
const dispose = require('../lib/dispose');
const ProfileForm = require('./ProfileForm');
/**
* Login - Handles dom and settings for the login box.
* @param {app} app - The app instance.
*/
function Login(app) {
this.app = app;
this.comm = this.app.comm;
// When logged in, an object containing user profile properties.
this._profile = ko.observable();
this.isLoggedIn = ko.observable(false);
this.emailObs = this.autoDispose(ko.computed(() => ((this._profile() && this._profile().email) || '')));
this.nameObs = this.autoDispose(ko.computed(() => ((this._profile() && this._profile().name) || '')));
this.buttonText = this.autoDispose(ko.computed(() =>
this.isLoggedIn() ? this.emailObs() : 'Log in'));
// Instantialized with createLoginForm() and createProfileForm()
this.profileForm = null;
}
dispose.makeDisposable(Login);
/**
* Returns the current profile object.
*/
Login.prototype.getProfile = function() {
return this._profile();
};
/**
* Opens the Cognito login form in a new browser window to allow the user to log in.
* The login tokens are sent back to the server to which this client belongs.
*/
Login.prototype.login = function() {
if (window.isRunningUnderElectron) {
// Under electron, we open the login URL (it opens in a user's default browser).
// With null for redirectUrl, it will close automatically when login completes.
return this.comm.getLoginUrl(null)
.then((loginUrl) => window.open(loginUrl));
} else {
// In hosted / dev version, we redirect to the login URL, and it will redirect back to the
// starting URL when login completes.
return this.comm.getLoginUrl(window.location.href)
.then((loginUrl) => { window.location.href = loginUrl; });
}
};
/**
* Tells the server to log out, and also opens a new window to the logout URL to get Cognito to
* clear its cookies. The new window will hit our page which will close the window automatically.
*/
Login.prototype.logout = function() {
// We both log out the server, and for hosted version, visit a logout URL to clear AWS cookies.
if (window.isRunningUnderElectron) {
// Under electron, only clear the server state. Don't open the user's default browser
// to clear cookies there because it serves dubious purpose and is annoying to the user.
return this.comm.logout(null);
} else {
// In hosted / dev version, we redirect to the logout URL, which will clear cookies and
// redirect back to the starting URL when logout completes.
return this.comm.logout(window.location.href)
.then((logoutUrl) => { window.location.href = logoutUrl; });
}
};
/**
* Retrieves the updated user profile from DynamoDB and creates the profile form.
* Also sends the fetched user profile to the server to keep it up to date.
*/
Login.prototype.createProfileForm = function() {
// ProfileForm disposes itself, no need to handle disposal.
this.profileForm = ProfileForm.create(this);
};
// Called when the user logs out in this or another tab.
Login.prototype.onLogout = function() {
this._profile(null);
this.isLoggedIn(false);
};
/**
* Update the internally-stored profile given a profile object from the server.
*/
Login.prototype.updateProfileFromServer = function(profileObj) {
this._profile(profileObj);
this.isLoggedIn(Boolean(this._profile.peek()));
};
Login.prototype.setProfileItem = function(key, val) {
return this.comm.updateProfile({[key]: val});
};
/**
* Returns an array of tableIds in the basket of the current document. If the current
* document has no basket, an empty array is returned.
*/
Login.prototype.getBasketTables = function(docComm) {
return docComm.getBasketTables();
};
// Execute func if the user is logged in. Otherwise, prompt the user to log in
// and then execute the function. Attempts refresh if the token is expired.
Login.prototype.tryWithLogin = function(func) {
return Promise.try(() => {
if (!this.isLoggedIn()) {
return this.login();
}
})
.then(() => func())
.catch(err => {
if (err.code === 'LoginClosedError') {
console.log("Login#tryWithLogin", err);
} else {
throw err;
}
});
};
module.exports = Login;