Merge pull request #31 from matrix-org/kegan/login-refactor
Refactor login page
This commit is contained in:
commit
9f7a504a20
6 changed files with 178 additions and 188 deletions
90
src/Signup.js
Normal file
90
src/Signup.js
Normal file
|
@ -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;
|
|
@ -16,10 +16,12 @@ limitations under the License.
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var MatrixClientPeg = require("../../MatrixClientPeg");
|
var MatrixClientPeg = require("../MatrixClientPeg");
|
||||||
|
var React = require('react');
|
||||||
var url = require("url");
|
var url = require("url");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = React.createClass({
|
||||||
|
displayName: 'CasLogin',
|
||||||
|
|
||||||
onCasClicked: function(ev) {
|
onCasClicked: function(ev) {
|
||||||
var cli = MatrixClientPeg.get();
|
var cli = MatrixClientPeg.get();
|
||||||
|
@ -30,4 +32,12 @@ module.exports = {
|
||||||
window.location.href = casUrl;
|
window.location.href = casUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button onClick={this.onCasClicked}>Sign in with CAS</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
65
src/components/login/PasswordLogin.js
Normal file
65
src/components/login/PasswordLogin.js
Normal file
|
@ -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 (
|
||||||
|
<div>
|
||||||
|
<form onSubmit={this.onSubmitForm}>
|
||||||
|
<input className="mx_Login_field" ref="user" type="text"
|
||||||
|
value={this.state.username} onChange={this.onUsernameChanged}
|
||||||
|
placeholder="Email or user name" />
|
||||||
|
<br />
|
||||||
|
<input className="mx_Login_field" ref="pass" type="password"
|
||||||
|
value={this.state.password} onChange={this.onPasswordChanged}
|
||||||
|
placeholder="Password" />
|
||||||
|
<br />
|
||||||
|
<input className="mx_Login_submit" type="submit" value="Log in" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
|
@ -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;
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -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({
|
this.setState({
|
||||||
screen: undefined,
|
screen: undefined,
|
||||||
logged_in: true
|
logged_in: true
|
||||||
|
@ -309,7 +316,8 @@ module.exports = {
|
||||||
var cli = MatrixClientPeg.get();
|
var cli = MatrixClientPeg.get();
|
||||||
var self = this;
|
var self = this;
|
||||||
cli.on('sync', function(state) {
|
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;
|
self.sdkReady = true;
|
||||||
|
|
||||||
if (self.starting_room_alias) {
|
if (self.starting_room_alias) {
|
||||||
|
|
|
@ -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'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
Loading…
Reference in a new issue