Merge pull request #381 from matrix-org/dbkr/deactivate_account
Implement account deactivation
This commit is contained in:
commit
0351ab0a3d
4 changed files with 171 additions and 6 deletions
|
@ -42,11 +42,11 @@ function logout() {
|
|||
// logout doesn't work for guest sessions
|
||||
// Also we sometimes want to re-log in a guest session
|
||||
// if we abort the login
|
||||
_onLoggedOut();
|
||||
onLoggedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
return MatrixClientPeg.get().logout().then(_onLoggedOut,
|
||||
return MatrixClientPeg.get().logout().then(onLoggedOut,
|
||||
(err) => {
|
||||
// Just throwing an error here is going to be very unhelpful
|
||||
// if you're trying to log out because your server's down and
|
||||
|
@ -56,7 +56,7 @@ function logout() {
|
|||
// tokens expire (and if you really think you've been compromised,
|
||||
// change your password).
|
||||
console.log("Failed to call logout API: token will not be invalidated");
|
||||
_onLoggedOut();
|
||||
onLoggedOut();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -79,7 +79,11 @@ function startMatrixClient() {
|
|||
MatrixClientPeg.start();
|
||||
}
|
||||
|
||||
function _onLoggedOut() {
|
||||
/*
|
||||
* Stops a running client and all related services, used after
|
||||
* a session has been logged out / ended.
|
||||
*/
|
||||
function onLoggedOut() {
|
||||
if (window.localStorage) {
|
||||
const hsUrl = window.localStorage.getItem("mx_hs_url");
|
||||
const isUrl = window.localStorage.getItem("mx_is_url");
|
||||
|
@ -95,7 +99,9 @@ function _onLoggedOut() {
|
|||
dis.dispatch({action: 'on_logged_out'});
|
||||
}
|
||||
|
||||
// stop all the background processes related to the current client
|
||||
/**
|
||||
* Stop all the background processes related to the current client
|
||||
*/
|
||||
function _stopMatrixClient() {
|
||||
Notifier.stop();
|
||||
UserActivity.stop();
|
||||
|
@ -106,5 +112,5 @@ function _stopMatrixClient() {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
setLoggedIn, logout, startMatrixClient
|
||||
setLoggedIn, logout, startMatrixClient, onLoggedOut
|
||||
};
|
||||
|
|
|
@ -45,6 +45,7 @@ module.exports.components['views.avatars.RoomAvatar'] = require('./components/vi
|
|||
module.exports.components['views.create_room.CreateRoomButton'] = require('./components/views/create_room/CreateRoomButton');
|
||||
module.exports.components['views.create_room.Presets'] = require('./components/views/create_room/Presets');
|
||||
module.exports.components['views.create_room.RoomAlias'] = require('./components/views/create_room/RoomAlias');
|
||||
module.exports.components['views.dialogs.DeactivateAccountDialog'] = require('./components/views/dialogs/DeactivateAccountDialog');
|
||||
module.exports.components['views.dialogs.ErrorDialog'] = require('./components/views/dialogs/ErrorDialog');
|
||||
module.exports.components['views.dialogs.LogoutPrompt'] = require('./components/views/dialogs/LogoutPrompt');
|
||||
module.exports.components['views.dialogs.NeedToRegisterDialog'] = require('./components/views/dialogs/NeedToRegisterDialog');
|
||||
|
|
|
@ -262,6 +262,11 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
_onDeactivateAccountClicked: function() {
|
||||
const DeactivateAccountDialog = sdk.getComponent("dialogs.DeactivateAccountDialog");
|
||||
Modal.createDialog(DeactivateAccountDialog, {});
|
||||
},
|
||||
|
||||
_renderUserInterfaceSettings: function() {
|
||||
var client = MatrixClientPeg.get();
|
||||
|
||||
|
@ -379,6 +384,20 @@ module.exports = React.createClass({
|
|||
)
|
||||
},
|
||||
|
||||
_renderDeactivateAccount: function() {
|
||||
// We can't deactivate a guest account.
|
||||
if (MatrixClientPeg.get().isGuest()) return null;
|
||||
|
||||
return <div>
|
||||
<h3>Deactivate Account</h3>
|
||||
<div className="mx_UserSettings_section">
|
||||
<button className="mx_UserSettings_button danger"
|
||||
onClick={this._onDeactivateAccountClicked}>Deactivate my account
|
||||
</button>
|
||||
</div>
|
||||
</div>;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
var Loader = sdk.getComponent("elements.Spinner");
|
||||
|
@ -548,6 +567,8 @@ module.exports = React.createClass({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{this._renderDeactivateAccount()}
|
||||
|
||||
</GeminiScrollbar>
|
||||
</div>
|
||||
);
|
||||
|
|
137
src/components/views/dialogs/DeactivateAccountDialog.js
Normal file
137
src/components/views/dialogs/DeactivateAccountDialog.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
Copyright 2016 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import sdk from '../../../index';
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import Lifecycle from '../../../Lifecycle';
|
||||
import Velocity from 'velocity-vector';
|
||||
|
||||
export default class DeactivateAccountDialog extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this._passwordField = null;
|
||||
|
||||
this._onOk = this._onOk.bind(this);
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onPasswordFieldChange = this._onPasswordFieldChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
confirmButtonEnabled: false,
|
||||
busy: false,
|
||||
errStr: null,
|
||||
};
|
||||
}
|
||||
|
||||
_onPasswordFieldChange(ev) {
|
||||
this.setState({
|
||||
confirmButtonEnabled: Boolean(ev.target.value),
|
||||
});
|
||||
}
|
||||
|
||||
_onOk() {
|
||||
// This assumes that the HS requires password UI auth
|
||||
// for this endpoint. In reality it could be any UI auth.
|
||||
this.setState({busy: true});
|
||||
MatrixClientPeg.get().deactivateAccount({
|
||||
type: 'm.login.password',
|
||||
user: MatrixClientPeg.get().credentials.userId,
|
||||
password: this._passwordField.value,
|
||||
}).done(() => {
|
||||
Lifecycle.onLoggedOut();
|
||||
this.props.onFinished(false);
|
||||
}, (err) => {
|
||||
let errStr = 'Unknown error';
|
||||
// https://matrix.org/jira/browse/SYN-744
|
||||
if (err.httpStatus == 401 || err.httpStatus == 403) {
|
||||
errStr = 'Incorrect password';
|
||||
Velocity(this._passwordField, "callout.shake", 300);
|
||||
}
|
||||
this.setState({
|
||||
busy: false,
|
||||
errStr: errStr,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_onCancel() {
|
||||
this.props.onFinished(false);
|
||||
}
|
||||
|
||||
render() {
|
||||
const Loader = sdk.getComponent("elements.Spinner");
|
||||
let passwordBoxClass = '';
|
||||
|
||||
let error = null;
|
||||
if (this.state.errStr) {
|
||||
error = <div className="error">
|
||||
{this.state.err_str}
|
||||
</div>
|
||||
passwordBoxClass = 'error';
|
||||
}
|
||||
|
||||
const okLabel = this.state.busy ? <Loader /> : 'Deactivate Account';
|
||||
const okEnabled = this.state.confirmButtonEnabled && !this.state.busy;
|
||||
|
||||
let cancelButton = null;
|
||||
if (!this.state.busy) {
|
||||
cancelButton = <button onClick={this._onCancel} autoFocus={true}>
|
||||
Cancel
|
||||
</button>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx_DeactivateAccountDialog">
|
||||
<div className="mx_Dialog_title danger">
|
||||
Deactivate Account
|
||||
</div>
|
||||
<div className="mx_Dialog_content">
|
||||
<p>This will make your account permanently unusable. You will not be able to re-register the same user ID.</p>
|
||||
|
||||
<p>This action is irreversible.</p>
|
||||
|
||||
<p>To continue, please enter your password.</p>
|
||||
|
||||
<p>Password:</p>
|
||||
<input
|
||||
type="password"
|
||||
onChange={this._onPasswordFieldChange}
|
||||
ref={(e) => {this._passwordField = e;}}
|
||||
className={passwordBoxClass}
|
||||
/>
|
||||
{error}
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<button
|
||||
className="mx_Dialog_primary danger"
|
||||
onClick={this._onOk}
|
||||
disabled={!okEnabled}
|
||||
>
|
||||
{okLabel}
|
||||
</button>
|
||||
|
||||
{cancelButton}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeactivateAccountDialog.propTypes = {
|
||||
onFinished: React.PropTypes.func.isRequired,
|
||||
};
|
Loading…
Reference in a new issue