From 4124a8dcffe40287c3c2537d7cc2bbe3713d1f7a Mon Sep 17 00:00:00 2001 From: Oliver Hunt Date: Mon, 12 Jun 2017 06:19:12 +0100 Subject: [PATCH 01/12] Save scroll state immediately before updating Signed-off-by: Oliver Hunt --- src/components/structures/ScrollPanel.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index a652bcc827..1f324d059f 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -160,6 +160,10 @@ module.exports = React.createClass({ this.checkFillState(); }, + componentWillUpdate: function(nextProps, nextState) { + this._saveScrollState(); + }, + componentDidUpdate: function() { // after adding event tiles, we may need to tweak the scroll (either to // keep at the bottom of the timeline, or to maintain the view after From ce42a9a06f0fb12bf0bf434e68fcfeae4d214566 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 9 Jun 2017 17:18:45 +0100 Subject: [PATCH 02/12] Replace MatrixChat.state.screen with 'view' 'screen' is overloaded, as it us used for the parameter of `showScreen` (and, by implication, `state.screenAfterLogin`). Attempt to clear up the confusion by replacing 'screen' with 'view' and using some constants for the potential values. This should be a no-op! --- src/components/structures/MatrixChat.js | 43 ++++++++++++++++--------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index efca22cc85..f6eb56c06f 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -43,6 +43,15 @@ import createRoom from "../../createRoom"; import * as UDEHandler from '../../UnknownDeviceErrorHandler'; import { _t, getCurrentLanguage } from '../../languageHandler'; +/** constants for MatrixChat.state.view */ +const VIEWS = { + DEFAULT: 0, + LOGIN: 1, + REGISTER: 2, + POST_REGISTRATION: 3, + FORGOT_PASSWORD: 4, +}; + module.exports = React.createClass({ displayName: 'MatrixChat', @@ -94,7 +103,11 @@ module.exports = React.createClass({ getInitialState: function() { const s = { loading: true, - screen: undefined, + + // the master view we are showing. + view: VIEWS.DEFAULT, + + // a thing to call showScreen with once login completes. screenAfterLogin: this.props.initialScreenAfterLogin, // Stashed guest credentials if the user logs out @@ -317,9 +330,9 @@ module.exports = React.createClass({ } }, - setStateForNewScreen: function(state) { + setStateForNewView: function(state) { const newState = { - screen: undefined, + view: VIEWS.DEFAULT, viewUserId: null, loggedIn: false, ready: false, @@ -347,19 +360,19 @@ module.exports = React.createClass({ guestCreds: MatrixClientPeg.getCredentials(), }); } - this.setStateForNewScreen({ - screen: 'login', + this.setStateForNewView({ + view: VIEWS.LOGIN, }); this.notifyNewScreen('login'); break; case 'start_post_registration': this.setState({ // don't clobber loggedIn status - screen: 'post_registration', + view: VIEWS.POST_REGISTRATION, }); break; case 'start_password_recovery': - this.setStateForNewScreen({ - screen: 'forgot_password', + this.setStateForNewView({ + view: VIEWS.FORGOT_PASSWORD, }); this.notifyNewScreen('forgot_password'); break; @@ -537,8 +550,8 @@ module.exports = React.createClass({ }, _startRegistration: function(params) { - this.setStateForNewScreen({ - screen: 'register', + this.setStateForNewView({ + view: VIEWS.REGISTER, // these params may be undefined, but if they are, // unset them from our state: we don't want to // resume a previous registration session if the @@ -969,7 +982,7 @@ module.exports = React.createClass({ */ _onLoggedOut: function() { this.notifyNewScreen('login'); - this.setStateForNewScreen({ + this.setStateForNewView({ loggedIn: false, ready: false, collapse_lhs: false, @@ -1253,7 +1266,7 @@ module.exports = React.createClass({ onFinishPostRegistration: function() { // Don't confuse this with "PageType" which is the middle window to show this.setState({ - screen: undefined, + view: VIEWS.DEFAULT, }); this.showScreen("settings"); }, @@ -1335,7 +1348,7 @@ module.exports = React.createClass({ } // needs to be before normal PageTypes as you are logged in technically - if (this.state.screen == 'post_registration') { + if (this.state.view === VIEWS.POST_REGISTRATION) { const PostRegistration = sdk.getComponent('structures.login.PostRegistration'); return ( ); - } else if (this.state.screen == 'register') { + } else if (this.state.view == VIEWS.REGISTER) { const Registration = sdk.getComponent('structures.login.Registration'); return ( ); - } else if (this.state.screen == 'forgot_password') { + } else if (this.state.view == VIEWS.FORGOT_PASSWORD) { const ForgotPassword = sdk.getComponent('structures.login.ForgotPassword'); return ( Date: Wed, 14 Jun 2017 20:04:55 +0100 Subject: [PATCH 03/12] MatrixChat: Replace state.{loading,loggedIn,loggingIn} with views MatrixChat is essentially a glorified state machine, with its states partially determined by the loading, loggedIn and loggingIn state flags. If we actually make each of the states implied by those flags an explicit 'view', then everything gets much clearer. --- src/components/structures/MatrixChat.js | 77 ++++++++++++++++--------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index f6eb56c06f..a34bafe086 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -45,14 +45,38 @@ import { _t, getCurrentLanguage } from '../../languageHandler'; /** constants for MatrixChat.state.view */ const VIEWS = { - DEFAULT: 0, + // a special initial state which is only used at startup, while we are + // trying to re-animate a matrix client or register as a guest. + LOADING: 0, + + // we are showing the login view LOGIN: 1, + + // we are showing the registration view REGISTER: 2, + + // completeing the registration flow POST_REGISTRATION: 3, + + // showing the 'forgot password' view FORGOT_PASSWORD: 4, + + // we have valid matrix credentials (either via an explicit login, via the + // initial re-animation/guest registration, or via a registration), and are + // now setting up a matrixclient to talk to it. This isn't an instant + // process because (a) we need to clear out indexeddb, and (b) we need to + LOGGING_IN: 5, + + // we are logged in with an active matrix client. + LOGGED_IN: 6, }; module.exports = React.createClass({ + // we export this so that the integration tests can use it :-S + statics: { + VIEWS: VIEWS, + }, + displayName: 'MatrixChat', propTypes: { @@ -102,10 +126,8 @@ module.exports = React.createClass({ getInitialState: function() { const s = { - loading: true, - // the master view we are showing. - view: VIEWS.DEFAULT, + view: VIEWS.LOADING, // a thing to call showScreen with once login completes. screenAfterLogin: this.props.initialScreenAfterLogin, @@ -126,8 +148,6 @@ module.exports = React.createClass({ // If we're trying to just view a user ID (i.e. /user URL), this is it viewUserId: null, - loggedIn: false, - loggingIn: false, collapse_lhs: false, collapse_rhs: false, ready: false, @@ -289,7 +309,6 @@ module.exports = React.createClass({ firstScreen === 'register' || firstScreen === 'forgot_password') { this.props.onLoadCompleted(); - this.setState({loading: false}); this._showScreenAfterLogin(); return; } @@ -331,17 +350,18 @@ module.exports = React.createClass({ }, setStateForNewView: function(state) { + if (state.view === undefined) { + throw new Error("setStateForNewView with no view!"); + } const newState = { - view: VIEWS.DEFAULT, viewUserId: null, - loggedIn: false, - ready: false, }; Object.assign(newState, state); this.setState(newState); }, onAction: function(payload) { + // console.log(`MatrixClientPeg.onAction: ${payload.action}`); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); @@ -366,7 +386,7 @@ module.exports = React.createClass({ this.notifyNewScreen('login'); break; case 'start_post_registration': - this.setState({ // don't clobber loggedIn status + this.setState({ view: VIEWS.POST_REGISTRATION, }); break; @@ -516,7 +536,10 @@ module.exports = React.createClass({ // and also that we're not ready (we'll be marked as logged // in once the login completes, then ready once the sync // completes). - this.setState({loggingIn: true, ready: false}); + this.setStateForNewView({ + view: VIEWS.LOGGING_IN, + ready: false, + }); break; case 'on_logged_in': this._onLoggedIn(payload.teamToken); @@ -864,7 +887,12 @@ module.exports = React.createClass({ */ _onLoadCompleted: function() { this.props.onLoadCompleted(); - this.setState({loading: false}); + + // if we've got this far without leaving the 'loading' view, then + // login must have failed, so start the login process + if (this.state.view === VIEWS.LOADING) { + dis.dispatch({action: "start_login"}); + } }, /** @@ -919,9 +947,8 @@ module.exports = React.createClass({ */ _onLoggedIn: function(teamToken) { this.setState({ + view: VIEWS.LOGGED_IN, guestCreds: null, - loggedIn: true, - loggingIn: false, }); if (teamToken) { @@ -983,7 +1010,7 @@ module.exports = React.createClass({ _onLoggedOut: function() { this.notifyNewScreen('login'); this.setStateForNewView({ - loggedIn: false, + view: VIEWS.LOGIN, ready: false, collapse_lhs: false, collapse_rhs: false, @@ -1146,7 +1173,7 @@ module.exports = React.createClass({ // we can't view a room unless we're logged in // (a guest account is fine) - if (this.state.loggedIn) { + if (this.state.view === VIEWS.LOGGED_IN) { dis.dispatch(payload); } } else if (screen.indexOf('user/') == 0) { @@ -1266,7 +1293,7 @@ module.exports = React.createClass({ onFinishPostRegistration: function() { // Don't confuse this with "PageType" which is the middle window to show this.setState({ - view: VIEWS.DEFAULT, + view: VIEWS.LOGGED_IN, }); this.showScreen("settings"); }, @@ -1334,11 +1361,9 @@ module.exports = React.createClass({ }, render: function() { - // `loading` might be set to false before `loggedIn = true`, causing the default - // (``) to be visible for a few MS (say, whilst a request is in-flight to - // the RTS). So in the meantime, use `loggingIn`, which is true between - // actions `on_logging_in` and `on_logged_in`. - if (this.state.loading || this.state.loggingIn) { + // console.log(`Rendering MatrixChat with view ${this.state.view}`); + + if (this.state.view === VIEWS.LOADING || this.state.view === VIEWS.LOGGING_IN) { const Spinner = sdk.getComponent('elements.Spinner'); return (
@@ -1356,10 +1381,10 @@ module.exports = React.createClass({ ); } - // `ready` and `loggedIn` may be set before `page_type` (because the + // `ready` and `view==LOGGED_IN` may be set before `page_type` (because the // latter is set via the dispatcher). If we don't yet have a `page_type`, // keep showing the spinner for now. - if (this.state.loggedIn && this.state.ready && this.state.page_type) { + if (this.state.view === VIEWS.LOGGED_IN && this.state.ready && this.state.page_type) { /* for now, we stuff the entirety of our props and state into the LoggedInView. * we should go through and figure out what we actually need to pass down, as well * as using something like redux to avoid having a billion bits of state kicking around. @@ -1376,7 +1401,7 @@ module.exports = React.createClass({ {...this.state} /> ); - } else if (this.state.loggedIn) { + } else if (this.state.view === VIEWS.LOGGED_IN) { // we think we are logged in, but are still waiting for the /sync to complete const Spinner = sdk.getComponent('elements.Spinner'); return ( From 7b526308fdf2f82e8c2ceb5b7f923ee0e5c24e0e Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 15 Jun 2017 17:36:57 +0100 Subject: [PATCH 04/12] Rearrange MatrixChat.render for sanity no-op to make it into a nice simple switch-like arrangement --- src/components/structures/MatrixChat.js | 79 ++++++++++++++----------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index a34bafe086..c63a0cfaca 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1381,38 +1381,42 @@ module.exports = React.createClass({ ); } - // `ready` and `view==LOGGED_IN` may be set before `page_type` (because the - // latter is set via the dispatcher). If we don't yet have a `page_type`, - // keep showing the spinner for now. - if (this.state.view === VIEWS.LOGGED_IN && this.state.ready && this.state.page_type) { - /* for now, we stuff the entirety of our props and state into the LoggedInView. - * we should go through and figure out what we actually need to pass down, as well - * as using something like redux to avoid having a billion bits of state kicking around. - */ - const LoggedInView = sdk.getComponent('structures.LoggedInView'); - return ( - - ); - } else if (this.state.view === VIEWS.LOGGED_IN) { - // we think we are logged in, but are still waiting for the /sync to complete - const Spinner = sdk.getComponent('elements.Spinner'); - return ( - - ); - } else if (this.state.view == VIEWS.REGISTER) { + if (this.state.view === VIEWS.LOGGED_IN) { + // `ready` and `view==LOGGED_IN` may be set before `page_type` (because the + // latter is set via the dispatcher). If we don't yet have a `page_type`, + // keep showing the spinner for now. + if (this.state.ready && this.state.page_type) { + /* for now, we stuff the entirety of our props and state into the LoggedInView. + * we should go through and figure out what we actually need to pass down, as well + * as using something like redux to avoid having a billion bits of state kicking around. + */ + const LoggedInView = sdk.getComponent('structures.LoggedInView'); + return ( + + ); + } else { + // we think we are logged in, but are still waiting for the /sync to complete + const Spinner = sdk.getComponent('elements.Spinner'); + return ( + + ); + } + } + + if (this.state.view === VIEWS.REGISTER) { const Registration = sdk.getComponent('structures.login.Registration'); return ( ); - } else if (this.state.view == VIEWS.FORGOT_PASSWORD) { + } + + + if (this.state.view === VIEWS.FORGOT_PASSWORD) { const ForgotPassword = sdk.getComponent('structures.login.ForgotPassword'); return ( ); - } else { + } + + if (this.state.view === VIEWS.LOGIN) { const Login = sdk.getComponent('structures.login.Login'); return ( ); } + + throw new Error(`Unknown view ${this.state.view}`); }, }); From 5e5639b7307e006a81c59545e91f7d53c4682b98 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 16 Jun 2017 11:50:53 +0100 Subject: [PATCH 05/12] Fix half-written comment --- src/components/structures/MatrixChat.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index c63a0cfaca..3dbde90141 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -65,6 +65,7 @@ const VIEWS = { // initial re-animation/guest registration, or via a registration), and are // now setting up a matrixclient to talk to it. This isn't an instant // process because (a) we need to clear out indexeddb, and (b) we need to + // talk to the team server; while it is going on we show a big spinner. LOGGING_IN: 5, // we are logged in with an active matrix client. From 3884c5ccf061411843e17f1305d2fd6dbe7f5693 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 16 Jun 2017 11:51:12 +0100 Subject: [PATCH 06/12] Log an error on unknown state instead of throwing --- src/components/structures/MatrixChat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 3dbde90141..2fde44aaeb 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1476,6 +1476,6 @@ module.exports = React.createClass({ ); } - throw new Error(`Unknown view ${this.state.view}`); + console.error(`Unknown view ${this.state.view}`); }, }); From eb1fc9ae2d19950b55f08e776404db6a05cfae1c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 16 Jun 2017 14:33:14 +0100 Subject: [PATCH 07/12] Avoid transitioning to loggedIn state during token login Fixes riot-web#4334 When we do a token login, don't carry on with the normal app startup (transitioning to the loggedIn state etc) - instead tell the app about the successful login and wait for it to redirect. Replace onLoadCompleted with onTokenLoginCompleted so that the app can see what it's supposed to be doing. --- src/Lifecycle.js | 102 +++++++++++++----------- src/components/structures/MatrixChat.js | 73 +++++++++-------- 2 files changed, 97 insertions(+), 78 deletions(-) diff --git a/src/Lifecycle.js b/src/Lifecycle.js index 39a159869c..1c5d35a642 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -35,26 +35,20 @@ import { _t } from './languageHandler'; * Called at startup, to attempt to build a logged-in Matrix session. It tries * a number of things: * - * 1. if we have a loginToken in the (real) query params, it uses that to log - * in. * - * 2. if we have a guest access token in the fragment query params, it uses + * 1. if we have a guest access token in the fragment query params, it uses * that. * - * 3. if an access token is stored in local storage (from a previous session), + * 2. if an access token is stored in local storage (from a previous session), * it uses that. * - * 4. it attempts to auto-register as a guest user. + * 3. it attempts to auto-register as a guest user. * * If any of steps 1-4 are successful, it will call {_doSetLoggedIn}, which in * turn will raise on_logged_in and will_start_client events. * * @param {object} opts * - * @param {object} opts.realQueryParams: string->string map of the - * query-parameters extracted from the real query-string of the starting - * URI. - * * @param {object} opts.fragmentQueryParams: string->string map of the * query-parameters extracted from the #-fragment of the starting URI. * @@ -70,7 +64,6 @@ import { _t } from './languageHandler'; * @returns {Promise} a promise which resolves when the above process completes. */ export function loadSession(opts) { - const realQueryParams = opts.realQueryParams || {}; const fragmentQueryParams = opts.fragmentQueryParams || {}; let enableGuest = opts.enableGuest || false; const guestHsUrl = opts.guestHsUrl; @@ -82,14 +75,6 @@ export function loadSession(opts) { enableGuest = false; } - if (realQueryParams.loginToken) { - if (!realQueryParams.homeserver) { - console.warn("Cannot log in with token: can't determine HS URL to use"); - } else { - return _loginWithToken(realQueryParams, defaultDeviceDisplayName); - } - } - if (enableGuest && fragmentQueryParams.guest_user_id && fragmentQueryParams.guest_access_token @@ -117,7 +102,26 @@ export function loadSession(opts) { }); } -function _loginWithToken(queryParams, defaultDeviceDisplayName) { +/** + * @param {Object} queryParams string->string map of the + * query-parameters extracted from the real query-string of the starting + * URI. + * + * @param {String} defaultDeviceDisplayName + * + * @returns {Promise} promise which resolves to true if we completed the token + * login, else false + */ +export function attemptTokenLogin(queryParams, defaultDeviceDisplayName) { + if (!queryParams.loginToken) { + return q(false); + } + + if (!queryParams.homeserver) { + console.warn("Cannot log in with token: can't determine HS URL to use"); + return q(false); + } + // create a temporary MatrixClient to do the login const client = Matrix.createClient({ baseUrl: queryParams.homeserver, @@ -130,17 +134,21 @@ function _loginWithToken(queryParams, defaultDeviceDisplayName) { }, ).then(function(data) { console.log("Logged in with token"); - return _doSetLoggedIn({ - userId: data.user_id, - deviceId: data.device_id, - accessToken: data.access_token, - homeserverUrl: queryParams.homeserver, - identityServerUrl: queryParams.identityServer, - guest: false, - }, true); - }, (err) => { + return _clearStorage().then(() => { + _persistCredentialsToLocalStorage({ + userId: data.user_id, + deviceId: data.device_id, + accessToken: data.access_token, + homeserverUrl: queryParams.homeserver, + identityServerUrl: queryParams.identityServer, + guest: false, + }); + return true; + }); + }).catch((err) => { console.error("Failed to log in with login token: " + err + " " + err.data); + return false; }); } @@ -322,23 +330,10 @@ async function _doSetLoggedIn(credentials, clearStorage) { // Resolves by default let teamPromise = Promise.resolve(null); - // persist the session + if (localStorage) { try { - localStorage.setItem("mx_hs_url", credentials.homeserverUrl); - localStorage.setItem("mx_is_url", credentials.identityServerUrl); - localStorage.setItem("mx_user_id", credentials.userId); - localStorage.setItem("mx_access_token", credentials.accessToken); - localStorage.setItem("mx_is_guest", JSON.stringify(credentials.guest)); - - // if we didn't get a deviceId from the login, leave mx_device_id unset, - // rather than setting it to "undefined". - // - // (in this case MatrixClient doesn't bother with the crypto stuff - // - that's fine for us). - if (credentials.deviceId) { - localStorage.setItem("mx_device_id", credentials.deviceId); - } + _persistCredentialsToLocalStorage(credentials); // The user registered as a PWLU (PassWord-Less User), the generated password // is cached here such that the user can change it at a later time. @@ -349,8 +344,6 @@ async function _doSetLoggedIn(credentials, clearStorage) { cachedPassword: credentials.password, }); } - - console.log("Session persisted for %s", credentials.userId); } catch (e) { console.warn("Error using local storage: can't persist session!", e); } @@ -379,6 +372,25 @@ async function _doSetLoggedIn(credentials, clearStorage) { startMatrixClient(); } +function _persistCredentialsToLocalStorage(credentials) { + localStorage.setItem("mx_hs_url", credentials.homeserverUrl); + localStorage.setItem("mx_is_url", credentials.identityServerUrl); + localStorage.setItem("mx_user_id", credentials.userId); + localStorage.setItem("mx_access_token", credentials.accessToken); + localStorage.setItem("mx_is_guest", JSON.stringify(credentials.guest)); + + // if we didn't get a deviceId from the login, leave mx_device_id unset, + // rather than setting it to "undefined". + // + // (in this case MatrixClient doesn't bother with the crypto stuff + // - that's fine for us). + if (credentials.deviceId) { + localStorage.setItem("mx_device_id", credentials.deviceId); + } + + console.log("Session persisted for %s", credentials.userId); +} + /** * Logs the current session out and transitions to the logged-out state */ diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index ab937c07ac..a4637d210d 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -59,8 +59,8 @@ module.exports = React.createClass({ // the initial queryParams extracted from the hash-fragment of the URI startingFragmentQueryParams: React.PropTypes.object, - // called when the session load completes - onLoadCompleted: React.PropTypes.func, + // called when we have completed a token login + onTokenLoginCompleted: React.PropTypes.func, // Represents the screen to display as a result of parsing the initial // window.location @@ -143,7 +143,7 @@ module.exports = React.createClass({ realQueryParams: {}, startingFragmentQueryParams: {}, config: {}, - onLoadCompleted: () => {}, + onTokenLoginCompleted: () => {}, }; }, @@ -266,39 +266,47 @@ module.exports = React.createClass({ const teamServerConfig = this.props.config.teamServerConfig || {}; Lifecycle.initRtsClient(teamServerConfig.teamServerURL); - // if the user has followed a login or register link, don't reanimate - // the old creds, but rather go straight to the relevant page + // the first thing to do is to try the token params in the query-string + Lifecycle.attemptTokenLogin(this.props.realQueryParams).then((loggedIn) => { + if(loggedIn) { + this.props.onTokenLoginCompleted(); - const firstScreen = this.state.screenAfterLogin ? - this.state.screenAfterLogin.screen : null; + // don't do anything else until the page reloads - just stay in + // the 'loading' state. + return; + } - if (firstScreen === 'login' || - firstScreen === 'register' || - firstScreen === 'forgot_password') { - this.props.onLoadCompleted(); - this.setState({loading: false}); - this._showScreenAfterLogin(); - return; - } + // if the user has followed a login or register link, don't reanimate + // the old creds, but rather go straight to the relevant page + const firstScreen = this.state.screenAfterLogin ? + this.state.screenAfterLogin.screen : null; - // the extra q() ensures that synchronous exceptions hit the same codepath as - // asynchronous ones. - q().then(() => { - return Lifecycle.loadSession({ - realQueryParams: this.props.realQueryParams, - fragmentQueryParams: this.props.startingFragmentQueryParams, - enableGuest: this.props.enableGuest, - guestHsUrl: this.getCurrentHsUrl(), - guestIsUrl: this.getCurrentIsUrl(), - defaultDeviceDisplayName: this.props.defaultDeviceDisplayName, + if (firstScreen === 'login' || + firstScreen === 'register' || + firstScreen === 'forgot_password') { + this.setState({loading: false}); + this._showScreenAfterLogin(); + return; + } + + // the extra q() ensures that synchronous exceptions hit the same codepath as + // asynchronous ones. + return q().then(() => { + return Lifecycle.loadSession({ + fragmentQueryParams: this.props.startingFragmentQueryParams, + enableGuest: this.props.enableGuest, + guestHsUrl: this.getCurrentHsUrl(), + guestIsUrl: this.getCurrentIsUrl(), + defaultDeviceDisplayName: this.props.defaultDeviceDisplayName, + }); + }).catch((e) => { + console.error("Unable to load session", e); + }).then(()=>{ + // stuff this through the dispatcher so that it happens + // after the on_logged_in action. + dis.dispatch({action: 'load_completed'}); }); - }).catch((e) => { - console.error("Unable to load session", e); - }).done(()=>{ - // stuff this through the dispatcher so that it happens - // after the on_logged_in action. - dis.dispatch({action: 'load_completed'}); - }); + }).done(); }, componentWillUnmount: function() { @@ -850,7 +858,6 @@ module.exports = React.createClass({ * Called when the sessionloader has finished */ _onLoadCompleted: function() { - this.props.onLoadCompleted(); this.setState({loading: false}); }, From db3d9c057349099e7186e8ab51d76f5e24a0a972 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 16 Jun 2017 12:20:52 +0100 Subject: [PATCH 08/12] Make Lifecycle.loadSession return an explicit result - rather than inferring it from the fact it didn't call logging_in. --- src/Lifecycle.js | 10 +++++++--- src/components/structures/MatrixChat.js | 24 ++++++------------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/Lifecycle.js b/src/Lifecycle.js index 1c5d35a642..3733ba1ea5 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -62,6 +62,8 @@ import { _t } from './languageHandler'; * true; defines the IS to use. * * @returns {Promise} a promise which resolves when the above process completes. + * Resolves to `true` if we ended up starting a session, or `false` if we + * failed. */ export function loadSession(opts) { const fragmentQueryParams = opts.fragmentQueryParams || {}; @@ -86,12 +88,12 @@ export function loadSession(opts) { homeserverUrl: guestHsUrl, identityServerUrl: guestIsUrl, guest: true, - }, true); + }, true).then(() => true); } return _restoreFromLocalStorage().then((success) => { if (success) { - return; + return true; } if (enableGuest) { @@ -99,6 +101,7 @@ export function loadSession(opts) { } // fall back to login screen + return false; }); } @@ -176,9 +179,10 @@ function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) { homeserverUrl: hsUrl, identityServerUrl: isUrl, guest: true, - }, true); + }, true).then(() => true); }, (err) => { console.error("Failed to register as guest: " + err + " " + err.data); + return false; }); } diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2c95386811..831fcdd9b2 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -335,10 +335,12 @@ module.exports = React.createClass({ }); }).catch((e) => { console.error("Unable to load session", e); - }).then(()=>{ - // stuff this through the dispatcher so that it happens - // after the on_logged_in action. - dis.dispatch({action: 'load_completed'}); + return false; + }).then((loadedSession) => { + if (!loadedSession) { + // fall back to showing the login screen + dis.dispatch({action: "start_login"}); + } }); }).done(); }, @@ -560,9 +562,6 @@ module.exports = React.createClass({ case 'will_start_client': this._onWillStartClient(); break; - case 'load_completed': - this._onLoadCompleted(); - break; case 'new_version': this.onVersion( payload.currentVersion, payload.newVersion, @@ -892,17 +891,6 @@ module.exports = React.createClass({ }); }, - /** - * Called when the sessionloader has finished - */ - _onLoadCompleted: function() { - // if we've got this far without leaving the 'loading' view, then - // login must have failed, so start the login process - if (this.state.view === VIEWS.LOADING) { - dis.dispatch({action: "start_login"}); - } - }, - /** * Called whenever someone changes the theme * From 7b4cd311242cb8a1e82746ae75933876d9125793 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 16 Jun 2017 16:12:52 +0100 Subject: [PATCH 09/12] make forward_message be friendly with the RVS stuffs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MatrixChat.js | 24 +++++++++++++++++ src/components/structures/RoomView.js | 15 ++++++----- src/components/views/rooms/ForwardMessage.js | 28 -------------------- src/stores/RoomViewStore.js | 21 +++++++++++++++ 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index ab937c07ac..7b1855b678 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -523,6 +523,9 @@ module.exports = React.createClass({ payload.releaseNotes, ); break; + case 'send_event': + this.onSendEvent(payload.room_id, payload.event); + break; } }, @@ -1267,6 +1270,27 @@ module.exports = React.createClass({ }); }, + onSendEvent: function(roomId, event) { + const cli = MatrixClientPeg.get(); + if (!cli) { + dis.dispatch({action: 'message_send_failed'}); + return; + } + + cli.sendEvent(roomId, event.getType(), event.getContent()).done(() => { + dis.dispatch({action: 'message_sent'}); + }, (err) => { + if (err.name === 'UnknownDeviceError') { + dis.dispatch({ + action: 'unknown_device_error', + err: err, + room: cli.getRoom(roomId), + }); + } + dis.dispatch({action: 'message_send_failed'}); + }); + }, + updateStatusIndicator: function(state, prevState) { let notifCount = 0; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 9306008e71..542b7a3e50 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -168,6 +168,7 @@ module.exports = React.createClass({ initialEventId: RoomViewStore.getInitialEventId(), initialEventPixelOffset: RoomViewStore.getInitialEventPixelOffset(), isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(), + forwardingEvent: RoomViewStore.getForwardingEvent(), }; // Temporary logging to diagnose https://github.com/vector-im/riot-web/issues/4307 @@ -452,11 +453,6 @@ module.exports = React.createClass({ callState: callState }); - break; - case 'forward_event': - this.setState({ - forwardingEvent: payload.content, - }); break; } }, @@ -1164,8 +1160,13 @@ module.exports = React.createClass({ this.updateTint(); this.setState({ editingRoomSettings: false, - forwardingEvent: null, }); + if (this.state.forwardingEvent) { + dis.dispatch({ + action: 'forward_event', + event: null, + }); + } dis.dispatch({action: 'focus_composer'}); }, @@ -1576,7 +1577,7 @@ module.exports = React.createClass({ } else if (this.state.uploadingRoomSettings) { aux = ; } else if (this.state.forwardingEvent !== null) { - aux = ; + aux = ; } else if (this.state.searching) { hideCancel = true; // has own cancel aux = ; diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js index 33df201d7c..3c97128a02 100644 --- a/src/components/views/rooms/ForwardMessage.js +++ b/src/components/views/rooms/ForwardMessage.js @@ -17,7 +17,6 @@ import React from 'react'; import { _t } from '../../../languageHandler'; -import MatrixClientPeg from '../../../MatrixClientPeg'; import dis from '../../../dispatcher'; import KeyCode from '../../../KeyCode'; @@ -26,11 +25,6 @@ module.exports = React.createClass({ displayName: 'ForwardMessage', propTypes: { - currentRoomId: React.PropTypes.string.isRequired, - - /* the MatrixEvent to be forwarded */ - mxEvent: React.PropTypes.object.isRequired, - onCancelClick: React.PropTypes.func.isRequired, }, @@ -44,7 +38,6 @@ module.exports = React.createClass({ }, componentDidMount: function() { - this.dispatcherRef = dis.register(this.onAction); document.addEventListener('keydown', this._onKeyDown); }, @@ -54,30 +47,9 @@ module.exports = React.createClass({ sideOpacity: 1.0, middleOpacity: 1.0, }); - dis.unregister(this.dispatcherRef); document.removeEventListener('keydown', this._onKeyDown); }, - onAction: function(payload) { - if (payload.action === 'view_room') { - const event = this.props.mxEvent; - const Client = MatrixClientPeg.get(); - Client.sendEvent(payload.room_id, event.getType(), event.getContent()).done(() => { - dis.dispatch({action: 'message_sent'}); - }, (err) => { - if (err.name === "UnknownDeviceError") { - dis.dispatch({ - action: 'unknown_device_error', - err: err, - room: Client.getRoom(payload.room_id), - }); - } - dis.dispatch({action: 'message_send_failed'}); - }); - if (this.props.currentRoomId === payload.room_id) this.props.onCancelClick(); - } - }, - _onKeyDown: function(ev) { switch (ev.keyCode) { case KeyCode.ESCAPE: diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js index ac06d41e81..d68373f0d5 100644 --- a/src/stores/RoomViewStore.js +++ b/src/stores/RoomViewStore.js @@ -55,6 +55,8 @@ const INITIAL_STATE = { // pixelOffset: the number of pixels the window is scrolled down // from the focussedEvent. scrollStateMap: {}, + + forwardingEvent: null, }; /** @@ -116,6 +118,11 @@ class RoomViewStore extends Store { case 'update_scroll_state': this._updateScrollState(payload); break; + case 'forward_event': + this._setState({ + forwardingEvent: payload.event, + }); + break; } } @@ -127,6 +134,7 @@ class RoomViewStore extends Store { initialEventId: payload.event_id, initialEventPixelOffset: undefined, isInitialEventHighlighted: payload.highlighted, + forwardingEvent: null, roomLoading: false, roomLoadError: null, }; @@ -141,6 +149,14 @@ class RoomViewStore extends Store { } } + if (this._state.forwardingEvent) { + dis.dispatch({ + action: 'send_event', + room_id: newState.roomId, + event: this._state.forwardingEvent, + }); + } + this._setState(newState); } else if (payload.room_alias) { // Resolve the alias and then do a second dispatch with the room ID acquired @@ -276,6 +292,11 @@ class RoomViewStore extends Store { getJoinError() { return this._state.joinError; } + + // The mxEvent if one is about to be forwarded + getForwardingEvent() { + return this._state.forwardingEvent; + } } let singletonRoomViewStore = null; From 022161b78f23e47499ee33fc1f12695fd226cb07 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 19 Jun 2017 00:08:24 +0100 Subject: [PATCH 10/12] fix broken vars --- src/i18n/strings/ru.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 8712d310e7..e12f8528b2 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -355,7 +355,7 @@ "Friday": "Пятница", "Saturday": "Суббота", "Sunday": "Воскресенье", - "%(weekDayName)s %(time)s": "%(weekDayName) %(time)", + "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", "Upload an avatar:": "Загрузите аватар:", "You need to be logged in.": "Вы должны быть авторизованы.", "You need to be able to invite users to do that.": "Вам необходимо пригласить пользователей чтобы сделать это.", @@ -946,8 +946,8 @@ "Would you like to accept or decline this invitation?": "Хотели бы вы подтвердить это приглашение или отклонить?", "(~%(count)s results).one": "(~%(count)s Результат)", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Не удается подключиться к домашнему серверу - проверьте подключение, убедитесь, что ваш сертификат SSL homeserver's SSL certificate действителен, и расширение браузера не блокирует запросы.", - "You have been banned from %(roomName)s by %(userName)s.": "%(userName) забанил Вас в % (roomName).", - "You have been kicked from %(roomName)s by %(userName)s.": "%(userName) выгнал Вас из %(roomName).", + "You have been banned from %(roomName)s by %(userName)s.": "%(userName)s забанил Вас в %(roomName)s.", + "You have been kicked from %(roomName)s by %(userName)s.": "%(userName)s выгнал Вас из %(roomName)s.", "You may wish to login with a different account, or add this email to this account.": "Вы можете войти в систему с другой учетной записью или добавить этот адрес email в эту учетную запись.", "Your home server does not support device management.": "Ваш домашний сервер не поддерживает управление устройствами.", "(could not connect media)": "(не удается подключиться к медиа)", From fac98d16ddb8271ba0e6856f9efe6d07b272dd40 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 19 Jun 2017 00:11:34 +0100 Subject: [PATCH 11/12] fix broken i18n --- src/i18n/strings/el.json | 8 ++++---- src/i18n/strings/hu.json | 2 +- src/i18n/strings/nl.json | 2 +- src/i18n/strings/ru.json | 4 ++-- src/i18n/strings/sv.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/i18n/strings/el.json b/src/i18n/strings/el.json index eb25cd9e16..cdfb558f3a 100644 --- a/src/i18n/strings/el.json +++ b/src/i18n/strings/el.json @@ -839,13 +839,13 @@ "Share message history with new users": "Διαμοιρασμός ιστορικού μηνυμάτων με τους νέους χρήστες", "numbullet": "απαρίθμηση", "%(severalUsers)sleft and rejoined %(repeats)s times": "%(severalUsers)s έφυγαν και ξανασυνδέθηκαν %(repeats)s φορές", - "%(oneUser)sleft and rejoined %(repeats)s times": "%(severalUsers)s έφυγε και ξανασυνδέθηκε %(repeats)s φορές", + "%(oneUser)sleft and rejoined %(repeats)s times": "%(oneUser)s έφυγε και ξανασυνδέθηκε %(repeats)s φορές", "%(severalUsers)sleft and rejoined": "%(severalUsers)s έφυγαν και ξανασυνδέθηκαν", - "%(oneUser)sleft and rejoined": "%(severalUsers)s έφυγε και ξανασυνδέθηκε", + "%(oneUser)sleft and rejoined": "%(oneUser)s έφυγε και ξανασυνδέθηκε", "%(severalUsers)shad their invitations withdrawn %(repeats)s times": "Οι %(severalUsers)s απέσυραν τις προσκλήσεις τους %(repeats)s φορές", - "%(oneUser)shad their invitation withdrawn %(repeats)s times": "Ο %(severalUsers)s απέσυρε την πρόσκληση του %(repeats)s φορές", + "%(oneUser)shad their invitation withdrawn %(repeats)s times": "Ο %(oneUser)s απέσυρε την πρόσκληση του %(repeats)s φορές", "%(severalUsers)shad their invitations withdrawn": "Οι %(severalUsers)s απέσυραν τις προσκλήσεις τους", - "%(oneUser)shad their invitation withdrawn": "Ο %(severalUsers)s απέσυρε την πρόσκληση του", + "%(oneUser)shad their invitation withdrawn": "Ο %(oneUser)s απέσυρε την πρόσκληση του", "You must join the room to see its files": "Πρέπει να συνδεθείτε στο δωμάτιο για να δείτε τα αρχεία του", "Reject all %(invitedRooms)s invites": "Απόρριψη όλων των προσκλήσεων %(invitedRooms)s", "Failed to invite the following users to the %(roomName)s room:": "Δεν ήταν δυνατή η πρόσκληση των χρηστών στο δωμάτιο %(roomName)s:", diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index 3cc449b1fc..696a548b4a 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -204,7 +204,7 @@ "Anyone who knows the room's link, apart from guests": "A vendégeken kívül bárki aki ismeri a szoba link-jét", "Anyone who knows the room's link, including guests": "Bárki aki tudja a szoba link-jét, még a vendégek is", "Are you sure?": "Biztos?", - "Are you sure you want to leave the room '%(roomName)s'?": "Biztos elhagyod a szobát?", + "Are you sure you want to leave the room '%(roomName)s'?": "Biztos elhagyod a szobát '%(roomName)s'?", "Are you sure you want to reject the invitation?": "Biztos elutasítod a meghívást?", "Are you sure you want to upload the following files?": "Biztos feltöltöd ezeket a fájlokat?", "Attachment": "Csatolmány", diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 04b0514c4d..1c1d27c42b 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -333,7 +333,7 @@ "Create an account": "Open een account", "Cryptography": "Cryptografie", "Current password": "Huidig wachtwoord", - "%(senderDisplayName)s removed the room name.": "%(senderDisplayName) heeft de naam van de kamer verwijderd.", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s heeft de naam van de kamer verwijderd.", "Create a new chat or reuse an existing one": "Maak een nieuwe chat aan of gebruik een reeds bestaande", "Create Room": "Maak een kamer", "Curve25519 identity key": "Curve25519 identiteits sleutel", diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index e12f8528b2..d69282a07e 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -246,7 +246,7 @@ "Failed to set up conference call": "Не удалось установить конференц-вызов", "Failed to verify email address: make sure you clicked the link in the email": "Не удалось подтвердить email-адрес: убедитесь что вы щелкнули по ссылке электронной почты", "Failure to create room": "Не удалось создать комнату", - "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId) изменил %(fromPowerLevel) на %(toPowerLevel)", + "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s изменил %(fromPowerLevel)s на %(toPowerLevel)s", "Guest users can't create new rooms. Please register to create room and start a chat.": "Гостевые пользователи не могут создавать новые комнаты. Зарегистрируйтесь для создания комнаты и чата.", "click to reveal": "нажать для открытия", "%(senderName)s invited %(targetName)s.": "%(senderName)s приглашает %(targetName)s.", @@ -524,7 +524,7 @@ "OK": "ОК", "Only people who have been invited": "Только приглашённые люди", "Passwords can't be empty": "Поля паролей не могут быть пустыми", - "%(senderName)s placed a %(callType)s call.": "%(senderName) выполнил %(callType) вызов.", + "%(senderName)s placed a %(callType)s call.": "%(senderName)s выполнил %(callType)s вызов.", "Please check your email and click on the link it contains. Once this is done, click continue.": "Пожалуйста, проверьте вашу электронную почту и нажмите в ней ссылку. По завершении нажмите продолжить.", "Power level must be positive integer.": "Уровень силы должен быть положительным числом.", "Press": "Нажать", diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index fe8b1ffee1..21bda3b741 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -296,7 +296,7 @@ "Active call (%(roomName)s)": "Aktiv samtal (%(roomName)s)", "Add": "Lägg till", "Admin tools": "Admin verktyg", - "And %(count)s more...": "Och %(count) till...", + "And %(count)s more...": "Och %(count)s till...", "Alias (optional)": "Alias (valfri)", "Can't connect to homeserver - please check your connectivity, ensure your homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Det gick inte att ansluta till servern - kontrollera anslutningen, försäkra att din hemservers TLS-certifikat är betrott, och att inget webbläsartillägg blockerar förfrågningar.", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ändrade maktnivån av %(powerLevelDiffText)s.", From 3b518f2c597d68ec811bc3424e86ef80d862d6dd Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 19 Jun 2017 10:22:18 +0100 Subject: [PATCH 12/12] Fix race in registration for pusher config we no longer immediately create the MatrixClient, so don't assume we do. --- src/Lifecycle.js | 7 +++++-- src/components/structures/MatrixChat.js | 3 ++- src/components/structures/login/Registration.js | 12 ++++++------ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Lifecycle.js b/src/Lifecycle.js index 3733ba1ea5..59580e7cb6 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -294,10 +294,12 @@ export function initRtsClient(url) { * storage before starting the new client. * * @param {MatrixClientCreds} credentials The credentials to use + * + * @returns {Promise} promise which resolves to the new MatrixClient once it has been started */ export function setLoggedIn(credentials) { stopMatrixClient(); - _doSetLoggedIn(credentials, true); + return _doSetLoggedIn(credentials, true); } /** @@ -307,7 +309,7 @@ export function setLoggedIn(credentials) { * @param {MatrixClientCreds} credentials * @param {Boolean} clearStorage * - * returns a Promise which resolves once the client has been started + * @returns {Promise} promise which resolves to the new MatrixClient once it has been started */ async function _doSetLoggedIn(credentials, clearStorage) { credentials.guest = Boolean(credentials.guest); @@ -374,6 +376,7 @@ async function _doSetLoggedIn(credentials, clearStorage) { }); startMatrixClient(); + return MatrixClientPeg.get(); } function _persistCredentialsToLocalStorage(credentials) { diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 26f0edf309..e2bb5764cc 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1280,13 +1280,14 @@ module.exports = React.createClass({ } }, + // returns a promise which resolves to the new MatrixClient onRegistered: function(credentials, teamToken) { // XXX: These both should be in state or ideally store(s) because we risk not // rendering the most up-to-date view of state otherwise. // teamToken may not be truthy this._teamToken = teamToken; this._is_registered = true; - Lifecycle.setLoggedIn(credentials); + return Lifecycle.setLoggedIn(credentials); }, onFinishPostRegistration: function() { diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js index 17fbf445b2..388198bb02 100644 --- a/src/components/structures/login/Registration.js +++ b/src/components/structures/login/Registration.js @@ -218,29 +218,29 @@ module.exports = React.createClass({ } trackPromise.then((teamToken) => { - this.props.onLoggedIn({ + return this.props.onLoggedIn({ userId: response.user_id, deviceId: response.device_id, homeserverUrl: this._matrixClient.getHomeserverUrl(), identityServerUrl: this._matrixClient.getIdentityServerUrl(), accessToken: response.access_token }, teamToken); - }).then(() => { - return this._setupPushers(); + }).then((cli) => { + return this._setupPushers(cli); }); }, - _setupPushers: function() { + _setupPushers: function(matrixClient) { if (!this.props.brand) { return q(); } - return MatrixClientPeg.get().getPushers().then((resp)=>{ + return matrixClient.getPushers().then((resp)=>{ const pushers = resp.pushers; for (let i = 0; i < pushers.length; ++i) { if (pushers[i].kind == 'email') { const emailPusher = pushers[i]; emailPusher.data = { brand: this.props.brand }; - MatrixClientPeg.get().setPusher(emailPusher).done(() => { + matrixClient.setPusher(emailPusher).done(() => { console.log("Set email branding to " + this.props.brand); }, (error) => { console.error("Couldn't set email branding: " + error);