diff --git a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 index 660456db7f5..8de322600d6 100644 --- a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 @@ -14,11 +14,13 @@ export default Ember.Component.extend({ Ember.run.scheduleOnce('afterRender', this, this._afterFirstRender); this.appEvents.on('modal-body:flash', msg => this._flash(msg)); + this.appEvents.on('modal-body:clearFlash', () => this._clearFlash()); }, willDestroyElement() { this._super(); this.appEvents.off('modal-body:flash'); + this.appEvents.off('modal-body:clearFlash'); }, _afterFirstRender() { @@ -45,10 +47,16 @@ export default Ember.Component.extend({ ); }, + _clearFlash() { + $('#modal-alert').hide().removeClass('alert-error', 'alert-success'); + }, + _flash(msg) { - $('#modal-alert').hide() - .removeClass('alert-error', 'alert-success') - .addClass(`alert alert-${msg.messageClass || 'success'}`).html(msg.text || '') - .fadeIn(); + this._clearFlash(); + + $('#modal-alert') + .addClass(`alert alert-${msg.messageClass || 'success'}`) + .html(msg.text || '') + .fadeIn(); }, }); diff --git a/app/assets/javascripts/discourse/components/login-buttons.js.es6 b/app/assets/javascripts/discourse/components/login-buttons.js.es6 index 4c68d1740f2..aa90e565c73 100644 --- a/app/assets/javascripts/discourse/components/login-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/login-buttons.js.es6 @@ -13,8 +13,12 @@ export default Ember.Component.extend({ }, actions: { - externalLogin: function(provider) { - this.sendAction('action', provider); + emailLogin() { + this.sendAction('emailLogin'); + }, + + externalLogin(provider) { + this.sendAction('externalLogin', provider); } } }); diff --git a/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 b/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 index 7e385fb3022..a5dff79c90f 100644 --- a/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 @@ -29,45 +29,36 @@ export default Ember.Controller.extend(ModalFunctionality, { }, resetPassword() { - return this._submit('/session/forgot_password', 'forgot_password.complete'); - }, + if (this.get('submitDisabled')) return false; + this.set('disabled', true); - emailLogin() { - return this._submit('/u/email-login', 'email_login.complete'); + this.clearFlash(); + + ajax('/session/forgot_password', { + data: { login: this.get('accountEmailOrUsername').trim() }, + type: 'POST' + }).then(data => { + const accountEmailOrUsername = escapeExpression(this.get("accountEmailOrUsername")); + const isEmail = accountEmailOrUsername.match(/@/); + let key = `forgot_password.complete_${isEmail ? 'email' : 'username'}`; + if (data.user_found) { + this.set('offerHelp', I18n.t(`${key}_found`, { + email: accountEmailOrUsername, + username: accountEmailOrUsername + })); + } else { + this.flash(I18n.t(`${key}_not_found`, { + email: accountEmailOrUsername, + username: accountEmailOrUsername + }), 'error'); + } + }).catch(e => { + this.flash(extractError(e), 'error'); + }).finally(() => { + this.set('disabled', false); + }); + + return false; } }, - - _submit(route, translationKey) { - if (this.get('submitDisabled')) return false; - this.set('disabled', true); - - ajax(route, { - data: { login: this.get('accountEmailOrUsername').trim() }, - type: 'POST' - }).then(data => { - const escaped = escapeExpression(this.get('accountEmailOrUsername')); - const isEmail = this.get('accountEmailOrUsername').match(/@/); - let key = `${translationKey}_${isEmail ? 'email' : 'username'}`; - let extraClass; - - if (data.user_found === true) { - key += '_found'; - this.set('accountEmailOrUsername', ''); - this.set('offerHelp', I18n.t(key, { email: escaped, username: escaped })); - } else { - if (data.user_found === false) { - key += '_not_found'; - extraClass = 'error'; - } - - this.flash(I18n.t(key, { email: escaped, username: escaped }), extraClass); - } - }).catch(e => { - this.flash(extractError(e), 'error'); - }).finally(() => { - this.set('disabled', false); - }); - - return false; - }, }); diff --git a/app/assets/javascripts/discourse/controllers/login.js.es6 b/app/assets/javascripts/discourse/controllers/login.js.es6 index 31d339b7c05..7646c8ecb34 100644 --- a/app/assets/javascripts/discourse/controllers/login.js.es6 +++ b/app/assets/javascripts/discourse/controllers/login.js.es6 @@ -4,6 +4,8 @@ import showModal from 'discourse/lib/show-modal'; import { setting } from 'discourse/lib/computed'; import { findAll } from 'discourse/models/login-method'; import { escape } from 'pretty-text/sanitizer'; +import { escapeExpression } from 'discourse/lib/utilities'; +import { extractError } from 'discourse/lib/ajax-error'; import computed from 'ember-addons/ember-computed-decorators'; // This is happening outside of the app via popup @@ -24,8 +26,10 @@ export default Ember.Controller.extend(ModalFunctionality, { authenticate: null, loggingIn: false, loggedIn: false, + processingEmailLink: false, canLoginLocal: setting('enable_local_logins'), + canLoginLocalWithEmail: setting('enable_local_logins_via_email'), loginRequired: Em.computed.alias('application.loginRequired'), resetForm: function() { @@ -59,6 +63,11 @@ export default Ember.Controller.extend(ModalFunctionality, { return this.get('loggingIn') || this.get('authenticate'); }.property('loggingIn', 'authenticate'), + @computed('canLoginLocalWithEmail', 'loginName', 'processingEmailLink') + showLoginWithEmailLink(canLoginLocalWithEmail, loginName, processingEmailLink) { + return canLoginLocalWithEmail && !Ember.isEmpty(loginName) && !processingEmailLink; + }, + actions: { login() { const self = this; @@ -198,6 +207,37 @@ export default Ember.Controller.extend(ModalFunctionality, { const forgotPasswordController = this.get('forgotPassword'); if (forgotPasswordController) { forgotPasswordController.set("accountEmailOrUsername", this.get("loginName")); } this.send("showForgotPassword"); + }, + + emailLogin() { + if (this.get('processingEmailLink')) { + return; + } + + if (Ember.isEmpty(this.get('loginName'))){ + this.flash(I18n.t('login.blank_username'), 'error'); + return; + } + + this.set('processingEmailLink', true); + + ajax('/u/email-login', { + data: { login: this.get('loginName').trim() }, + type: 'POST' + }).then(data => { + const loginName = escapeExpression(this.get('loginName')); + const isEmail = loginName.match(/@/); + let key = `email_login.complete_${isEmail ? 'email' : 'username'}`; + if (data.user_found) { + this.flash(I18n.t(`${key}_found`, { email: loginName, username: loginName })); + } else { + this.flash(I18n.t(`${key}_not_found`, { email: loginName, username: loginName }), 'error'); + } + }).catch(e => { + this.flash(extractError(e), 'error'); + }).finally(() => { + this.set('processingEmailLink', false); + }); } }, diff --git a/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 b/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 index d78478dae63..b34b906bdcd 100644 --- a/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 +++ b/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 @@ -5,6 +5,10 @@ export default Ember.Mixin.create({ this.appEvents.trigger('modal-body:flash', { text, messageClass }); }, + clearFlash() { + this.appEvents.trigger('modal-body:clearFlash'); + }, + showModal(...args) { return showModal(...args); }, diff --git a/app/assets/javascripts/discourse/templates/components/login-buttons.hbs b/app/assets/javascripts/discourse/templates/components/login-buttons.hbs index 776ddff179e..bdd430c4e7a 100644 --- a/app/assets/javascripts/discourse/templates/components/login-buttons.hbs +++ b/app/assets/javascripts/discourse/templates/components/login-buttons.hbs @@ -1,3 +1,12 @@ {{#each buttons as |b|}} {{/each}} + +{{#if canLoginLocalWithEmail}} + {{d-button + action="emailLogin" + label="email_login.button_label" + disabled=processingEmailLink + icon="envelope-o" + class="login-with-email-button"}} +{{/if}} diff --git a/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs b/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs index 02ccc7820ee..41353ac8ed1 100644 --- a/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/modal/login.hbs @@ -1,6 +1,11 @@ {{#login-modal screenX=lastX screenY=lastY loginName=loginName loginPassword=loginPassword loginSecondFactor=loginSecondFactor action="login"}} {{#d-modal-body title="login.title" class="login-modal"}} - {{login-buttons action="externalLogin"}} + {{login-buttons + canLoginLocalWithEmail=canLoginLocalWithEmail + processingEmailLink=processingEmailLink + emailLogin='emailLogin' + externalLogin='externalLogin'}} + {{#if canLoginLocal}}