diff --git a/src/Signup.js b/src/Signup.js new file mode 100644 index 0000000000..ba91ff60b0 --- /dev/null +++ b/src/Signup.js @@ -0,0 +1,90 @@ +"use strict"; +var MatrixClientPeg = require("./MatrixClientPeg"); +var dis = require("./dispatcher"); +var q = require("q"); + +class Register { + +} + +class Login { + constructor(hsUrl, isUrl) { + this._hsUrl = hsUrl; + this._isUrl = isUrl; + this._currentFlowIndex = 0; + this._flows = []; + } + + getFlows() { + var self = this; + // feels a bit wrong to be clobbering the global client for something we + // don't even know if it'll work, but we'll leave this here for now to + // not complicate matters further. It would be nicer to isolate this + // logic entirely from the rest of the app though. + MatrixClientPeg.replaceUsingUrls( + this._hsUrl, + this._isUrl + ); + return MatrixClientPeg.get().loginFlows().then(function(result) { + self._flows = result.flows; + self._currentFlowIndex = 0; + // technically the UI should display options for all flows for the + // user to then choose one, so return all the flows here. + return self._flows; + }); + } + + chooseFlow(flowIndex) { + this._currentFlowIndex = flowIndex; + } + + getCurrentFlowStep() { + // technically the flow can have multiple steps, but no one does this + // for login so we can ignore it. + var flowStep = this._flows[this._currentFlowIndex]; + return flowStep ? flowStep.type : null; + } + + loginViaPassword(username, pass) { + var self = this; + var isEmail = username.indexOf("@") > 0; + var loginParams = { + password: pass + }; + if (isEmail) { + loginParams.medium = 'email'; + loginParams.address = username; + } else { + loginParams.user = username; + } + + return MatrixClientPeg.get().login('m.login.password', loginParams).then(function(data) { + return q({ + homeserverUrl: self._hsUrl, + identityServerUrl: self._isUrl, + userId: data.user_id, + accessToken: data.access_token + }); + }, function(error) { + if (error.httpStatus == 400 && loginParams.medium) { + error.friendlyText = ( + 'This Home Server does not support login using email address.' + ); + } + else if (error.httpStatus === 403) { + error.friendlyText = ( + 'Incorrect username and/or password.' + ); + } + else { + error.friendlyText = ( + 'There was a problem logging in. (HTTP ' + error.httpStatus + ")" + ); + } + throw error; + }); + } +} + +module.exports.Register = Register; +module.exports.Login = Login; diff --git a/src/controllers/organisms/CasLogin.js b/src/components/login/CasLogin.js similarity index 75% rename from src/controllers/organisms/CasLogin.js rename to src/components/login/CasLogin.js index d84306e587..32116a3f76 100644 --- a/src/controllers/organisms/CasLogin.js +++ b/src/components/login/CasLogin.js @@ -16,10 +16,12 @@ limitations under the License. 'use strict'; -var MatrixClientPeg = require("../../MatrixClientPeg"); +var MatrixClientPeg = require("../MatrixClientPeg"); +var React = require('react'); var url = require("url"); -module.exports = { +module.exports = React.createClass({ + displayName: 'CasLogin', onCasClicked: function(ev) { var cli = MatrixClientPeg.get(); @@ -30,4 +32,12 @@ module.exports = { window.location.href = casUrl; }, -}; + render: function() { + return ( +
+ +
+ ); + } + +}); diff --git a/src/components/login/PasswordLogin.js b/src/components/login/PasswordLogin.js new file mode 100644 index 0000000000..fabd71d67e --- /dev/null +++ b/src/components/login/PasswordLogin.js @@ -0,0 +1,65 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +var React = require('react'); +var ReactDOM = require('react-dom'); + +/** + * A pure UI component which displays a username/password form. + */ +module.exports = React.createClass({displayName: 'PasswordLogin', + propTypes: { + onSubmit: React.PropTypes.func.isRequired // fn(username, password) + }, + + getInitialState: function() { + return { + username: "", + password: "" + }; + }, + + onSubmitForm: function(ev) { + ev.preventDefault(); + this.props.onSubmit(this.state.username, this.state.password); + }, + + onUsernameChanged: function(ev) { + this.setState({username: ev.target.value}); + }, + + onPasswordChanged: function(ev) { + this.setState({password: ev.target.value}); + }, + + render: function() { + return ( +
+
+ +
+ +
+ +
+
+ ); + } +}); \ No newline at end of file diff --git a/src/controllers/molecules/ServerConfig.js b/src/controllers/molecules/ServerConfig.js deleted file mode 100644 index 77fcb1d8c5..0000000000 --- a/src/controllers/molecules/ServerConfig.js +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require("react"); - -module.exports = { - propTypes: { - onHsUrlChanged: React.PropTypes.func, - onIsUrlChanged: React.PropTypes.func, - defaultHsUrl: React.PropTypes.string, - defaultIsUrl: React.PropTypes.string - }, - - getDefaultProps: function() { - return { - onHsUrlChanged: function() {}, - onIsUrlChanged: function() {}, - defaultHsUrl: 'https://matrix.org/', - defaultIsUrl: 'https://matrix.org/' - }; - }, - - getInitialState: function() { - return { - hs_url: this.props.defaultHsUrl, - is_url: this.props.defaultIsUrl, - original_hs_url: this.props.defaultHsUrl, - original_is_url: this.props.defaultIsUrl, - } - }, - - hsChanged: function(ev) { - this.setState({hs_url: ev.target.value}, function() { - this.props.onHsUrlChanged(this.state.hs_url); - }); - }, - - // XXX: horrible naming due to potential confusion between the word 'is' and the acronym 'IS' - isChanged: function(ev) { - this.setState({is_url: ev.target.value}, function() { - this.props.onIsUrlChanged(this.state.is_url); - }); - }, - - getHsUrl: function() { - return this.state.hs_url; - }, - - getIsUrl: function() { - return this.state.is_url; - }, -}; diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js index 4990a9488a..c2f0589688 100644 --- a/src/controllers/pages/MatrixChat.js +++ b/src/controllers/pages/MatrixChat.js @@ -295,7 +295,14 @@ module.exports = { } }, - onLoggedIn: function() { + onLoggedIn: function(credentials) { + if (credentials) { // registration doesn't do this yet + console.log("onLoggedIn => %s", credentials.userId); + MatrixClientPeg.replaceUsingAccessToken( + credentials.homeserverUrl, credentials.identityServerUrl, + credentials.userId, credentials.accessToken + ); + } this.setState({ screen: undefined, logged_in: true @@ -309,7 +316,8 @@ module.exports = { var cli = MatrixClientPeg.get(); var self = this; cli.on('sync', function(state) { - if (self.sdkReady || state !== "PREPARED") { return; } + console.log("MatrixClient sync state => %s", state); + if (state !== "PREPARED") { return; } self.sdkReady = true; if (self.starting_room_alias) { diff --git a/src/controllers/templates/Login.js b/src/controllers/templates/Login.js deleted file mode 100644 index 3c3a40e53a..0000000000 --- a/src/controllers/templates/Login.js +++ /dev/null @@ -1,116 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var MatrixClientPeg = require("../../MatrixClientPeg"); -var dis = require("../../dispatcher"); - -module.exports = { - getInitialState: function() { - return { - step: 'choose_hs', - busy: false, - currentStep: 0, - totalSteps: 1 - }; - }, - - setStep: function(step) { - this.setState({ step: step, busy: false }); - }, - - onHSChosen: function() { - MatrixClientPeg.replaceUsingUrls( - // XXX: why is the controller invoking methods from the view? :( -matthew - this.getHsUrl(), - this.getIsUrl() - ); - this.setState({ - hs_url: this.getHsUrl(), - is_url: this.getIsUrl(), - }); - this.setStep("fetch_stages"); - var cli = MatrixClientPeg.get(); - this.setState({ - busy: true, - errorText: "", - }); - var self = this; - cli.loginFlows().done(function(result) { - self.setState({ - flows: result.flows, - currentStep: 1, - totalSteps: result.flows.length+1 - }); - self.setStep('stage_'+result.flows[0].type); - }, function(error) { - self.setStep("choose_hs"); - self.setState({errorText: 'Unable to contact the given home server'}); - }); - }, - - onUserPassEntered: function(ev) { - ev.preventDefault(); - this.setState({ - busy: true, - errorText: "", - }); - var self = this; - - var formVals = this.getFormVals(); - - var loginParams = { - password: formVals.password - }; - if (formVals.username.indexOf('@') > 0) { - loginParams.medium = 'email'; - loginParams.address = formVals.username; - } else { - loginParams.user = formVals.username; - } - - MatrixClientPeg.get().login('m.login.password', loginParams).done(function(data) { - MatrixClientPeg.replaceUsingAccessToken( - self.state.hs_url, self.state.is_url, - data.user_id, data.access_token - ); - if (self.props.onLoggedIn) { - self.props.onLoggedIn(); - } - }, function(error) { - self.setStep("stage_m.login.password"); - if (error.httpStatus == 400 && loginParams.medium) { - self.setState({errorText: 'This Home Server does not support login using email address.'}); - } - else if (error.httpStatus === 403) { - self.setState({errorText: 'Incorrect username and/or password.'}); - } - else { - self.setState({ - errorText: 'There was a problem logging in. (HTTP ' + error.httpStatus + ")" - }); - } - }); - }, - - showRegister: function(ev) { - ev.preventDefault(); - dis.dispatch({ - action: 'start_registration' - }); - } -};