Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
215 lines
8.1 KiB
JavaScript
Executable file
215 lines
8.1 KiB
JavaScript
Executable file
/**
|
|
* Show a spinner in for two possible steps in the setup of an account:
|
|
*
|
|
* 1) During the autoconfig step, when figuring out the capabilities of the
|
|
* server, and possibly needing an oauth jump.
|
|
*
|
|
* 2) During the manual config or password flow when finally connecting to the
|
|
* service to confirm password and settings are correct.
|
|
*
|
|
* So the possible flows are:
|
|
*
|
|
* OAuth: setup_account_info -> setup_progress -> setup_account_prefs
|
|
* autoconfig password: setup_account_info -> setup_progress ->
|
|
* setup_password -> setup_progress -> setup_account_prefs
|
|
* manual config: setup_account_info -> setup_manual_config ->
|
|
* setup_progress -> setup_account_prefs
|
|
*/
|
|
'use strict';
|
|
define(function(require) {
|
|
|
|
var MailAPI = require('api'),
|
|
cards = require('cards'),
|
|
oauthFetch = require('cards/oauth2/fetch');
|
|
|
|
return [
|
|
require('./base_card')(require('template!./setup_progress.html')),
|
|
{
|
|
onArgs: function(args) {
|
|
this.args = args;
|
|
this.callingCard = args.callingCard;
|
|
this.creationInProcess = true;
|
|
this.pushedSecondaryCard = false;
|
|
this.cardHasBeenShown = false;
|
|
this.createCanceled = false;
|
|
},
|
|
|
|
extraClasses: ['anim-fade', 'anim-overlay'],
|
|
|
|
cancelCreation: function() {
|
|
if (!this.creationInProcess) {
|
|
return;
|
|
}
|
|
// XXX implement cancellation
|
|
},
|
|
|
|
onCardVisible: function() {
|
|
if (this.cardHasBeenShown) {
|
|
// If this card was made visible because of a cancel of a secondary
|
|
// config card, just go back one more card. The setTimeout is a hack.
|
|
// Without it, the final card is not actionable because the
|
|
// onTransitionEnd is not fired on this second removeCardAndSuccessors
|
|
// call while done as part of finishing up the previous card's
|
|
// removeCardAndSuccessors. A queue approach as described in 973038 does
|
|
// not help. It seems like the _transitionEnd for the second call does
|
|
// not ever fire. Need some async delay, not sure why yet. Otherwise,
|
|
// _eatingEventsUntilNextCard ends up as true, since the reset logic for
|
|
// it in _onTransitionEnd does not fire. An immediate setTimeout is not
|
|
// enough, bothersome that it needs a time threshold.
|
|
// pushedSecondaryCard is needed besides just a cardHasBeenShown,
|
|
// because this card calls the oauth code, which may show its own cards,
|
|
// but then navigate back to this card for a moment. In that case, the
|
|
// card needs to stay up and visible.
|
|
if (this.pushedSecondaryCard) {
|
|
setTimeout(this.onBack.bind(this), 100);
|
|
}
|
|
} else {
|
|
// First time the card has been shown, can now sort out what card to
|
|
// show next. This logic could be in onArgs, but it is racy, where
|
|
// learnAbout could complete before the animation to this card completes
|
|
// which would lead to a case where think we have pushed a secondary
|
|
// card, but it is really the first time this card is shown, so it would
|
|
// be hard to know if this card was being shown for first time setup
|
|
// reasons, or because a cancel/back had occurred. Ideally, learnAbout()
|
|
// would be called in setup_account_info, but since it could take a
|
|
// moment to complete by waiting for network connections to complete as
|
|
// part of autodiscovery, this card is shown to give the user feedback
|
|
// that something is happening. Instead of using the card visible state
|
|
// as a hack to know the cancel state, switch to a callingCard card
|
|
// passing approach so the next card can give a specific callingCard
|
|
// cancel signal. However, bug 973038 needs to be solved, or some way
|
|
// to remove more than one card at a time. Passing `2` to the
|
|
// removeCardAndSuccessors call from this card if callingCard cancel
|
|
// signal was received would also work, if we get proper expectations
|
|
// around the number of ontransitioned events in that case.
|
|
this.cardHasBeenShown = true;
|
|
if (!this.args.password) {
|
|
this.learnAbout();
|
|
} else {
|
|
// The manual config pathway.
|
|
this.tryCreate();
|
|
}
|
|
}
|
|
},
|
|
|
|
onBack: function(e) {
|
|
if (e) {
|
|
e.preventDefault();
|
|
}
|
|
this.cancelCreation();
|
|
this.createCanceled = true;
|
|
cards.removeCardAndSuccessors(this, 'animate', 1);
|
|
},
|
|
|
|
/**
|
|
* Trigger the back-end's autoconfig logic based on just knowing the user's
|
|
* email address to figure out what to do next.
|
|
*/
|
|
learnAbout: function() {
|
|
MailAPI.learnAboutAccount({
|
|
emailAddress: this.args.emailAddress
|
|
}, function(details) {
|
|
var args = this.args;
|
|
args.configInfo = details.configInfo;
|
|
var result = details.result;
|
|
|
|
// - We can autoconfig and it's time to use oauth!
|
|
if (result === 'need-oauth2') {
|
|
oauthFetch(details.configInfo.oauth2Settings, {
|
|
login_hint: args.emailAddress
|
|
})
|
|
.then(function(response) {
|
|
// Cancellation means lose the progress card and go back to entering
|
|
// the user's email address.
|
|
if (response.status === 'cancel') {
|
|
this.onBack();
|
|
// Successful oauth'ing means time to complete the account creation.
|
|
} else if (response.status === 'success') {
|
|
args.configInfo.oauth2Secrets = response.secrets;
|
|
args.configInfo.oauth2Tokens = response.tokens;
|
|
this.tryCreate();
|
|
// Any other error means things did not work. Things not working
|
|
// implies things will never work and so let's dump the user into
|
|
// the manual config card.
|
|
} else {
|
|
console.error('Unknown oauthFetch status: ' + response.status);
|
|
this._divertToManualConfig();
|
|
}
|
|
}.bind(this), this.onCreationError.bind(this));
|
|
// We can autoconfig but we need the user's password.
|
|
} else if (result === 'need-password') {
|
|
// Track that a secondary card was added that could lead to a cancel
|
|
// in that case, need to cancel this card too.
|
|
this.pushedSecondaryCard = true;
|
|
cards.pushCard(
|
|
'setup_account_password', 'animate',
|
|
{
|
|
displayName: args.displayName,
|
|
emailAddress: args.emailAddress
|
|
},
|
|
'right');
|
|
// No configuration data available, the user's only option is manual
|
|
// config.
|
|
} else { // must be no-config-info and even if not, we'd want this.
|
|
this._divertToManualConfig();
|
|
}
|
|
}.bind(this));
|
|
},
|
|
|
|
/**
|
|
* learnAbout decided the only option for the user is to manually configure
|
|
* their account. Sorry, user!
|
|
*/
|
|
_divertToManualConfig: function() {
|
|
this.pushedSecondaryCard = true;
|
|
cards.pushCard('setup_manual_config', 'animate', {
|
|
displayName: this.args.displayName,
|
|
emailAddress: this.args.emailAddress
|
|
},
|
|
'right');
|
|
},
|
|
|
|
tryCreate: function() {
|
|
var args = this.args;
|
|
var options = {
|
|
displayName: args.displayName,
|
|
emailAddress: args.emailAddress,
|
|
password: args.password,
|
|
outgoingPassword: args.outgoingPassword
|
|
};
|
|
|
|
MailAPI.tryToCreateAccount(
|
|
options,
|
|
args.configInfo || null,
|
|
function(err, errDetails, account) {
|
|
this.creationInProcess = false;
|
|
if (err) {
|
|
this.onCreationError(err, errDetails);
|
|
} else {
|
|
if (this.createCanceled) {
|
|
account.deleteAccount();
|
|
} else {
|
|
this.onCreationSuccess(account);
|
|
}
|
|
}
|
|
}.bind(this));
|
|
},
|
|
|
|
onCreationError: function(err, errDetails) {
|
|
this.callingCard.showError(err, errDetails);
|
|
cards.removeCardAndSuccessors(this, 'animate', 1);
|
|
},
|
|
|
|
onCreationSuccess: function(account) {
|
|
cards.pushCard('setup_account_prefs', 'animate',
|
|
{
|
|
account: account
|
|
});
|
|
},
|
|
|
|
die: function() {
|
|
this.cancelCreation();
|
|
}
|
|
}
|
|
];
|
|
});
|