blob: d4d1abb760ee8b2a05f5487cd3f1b12db7e05ad0 [file] [log] [blame]
// 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.
define([
'app',
'api',
'react',
'addons/auth/stores',
'addons/auth/actions'
], function (app, FauxtonAPI, React, AuthStores, AuthActions) {
var changePasswordStore = AuthStores.changePasswordStore;
var createAdminStore = AuthStores.createAdminStore;
var createAdminSidebarStore = AuthStores.createAdminSidebarStore;
var LoginForm = React.createClass({
propTypes: {
urlBack: React.PropTypes.string.isRequired
},
getInitialState: function () {
return {
username: '',
password: ''
};
},
getDefaultProps: function () {
return {
urlBack: '',
// for testing purposes only
testBlankUsername: null,
testBlankPassword: null
};
},
onInputChange: function (e) {
var change = (e.target.name === 'name') ? { username: e.target.value } : { password: e.target.value };
this.setState(change);
},
submit: function (e) {
e.preventDefault();
if (!this.checkUnrecognizedAutoFill()) {
this.login(this.state.username, this.state.password);
}
},
// Safari has a bug where autofill doesn't trigger a change event. This checks for the condition where the state
// and form fields have a mismatch. See: https://issues.apache.org/jira/browse/COUCHDB-2829
checkUnrecognizedAutoFill: function () {
if (this.state.username !== '' || this.state.password !== '') {
return false;
}
var username = (this.props.testBlankUsername) ? this.props.testBlankUsername : React.findDOMNode(this.refs.username).value;
var password = (this.props.testBlankPassword) ? this.props.testBlankPassword : React.findDOMNode(this.refs.password).value;
this.setState({ username: username, password: password }); // doesn't set immediately, hence separate login() call
this.login(username, password);
return true;
},
login: function (username, password) {
AuthActions.login(username, password, this.props.urlBack);
},
componentDidMount: function () {
React.findDOMNode(this.refs.username).focus();
},
render: function () {
return (
<div className="row-fluid">
<div className="span12">
<form id="login" onSubmit={this.submit}>
<p className="help-block">
Login with your username and password
</p>
<input id="username" type="text" name="name" ref="username" placeholder="Username" size="24"
onChange={this.onInputChange} value={this.state.username} />
<br/>
<input id="password" type="password" name="password" ref="password" placeholder="Password" size="24"
onChange={this.onInputChange} value={this.state.password} />
<br/>
<button id="submit" className="btn" type="submit">Login</button>
</form>
</div>
</div>
);
}
});
var ChangePasswordForm = React.createClass({
getInitialState: function () {
return this.getStoreState();
},
getStoreState: function () {
return {
password: changePasswordStore.getChangePassword(),
passwordConfirm: changePasswordStore.getChangePasswordConfirm()
};
},
onChange: function () {
this.setState(this.getStoreState());
},
onChangePassword: function (e) {
AuthActions.updateChangePasswordField(e.target.value);
},
onChangePasswordConfirm: function (e) {
AuthActions.updateChangePasswordConfirmField(e.target.value);
},
componentDidMount: function () {
React.findDOMNode(this.refs.password).focus();
changePasswordStore.on('change', this.onChange, this);
},
componentWillUnmount: function () {
changePasswordStore.off('change', this.onChange);
},
changePassword: function (e) {
e.preventDefault();
AuthActions.changePassword(this.state.password, this.state.passwordConfirm);
},
render: function () {
return (
<div className="auth-page">
<h3>Change Password</h3>
<form id="change-password" onSubmit={this.changePassword}>
<p>
Enter your new password.
</p>
<input id="password" type="password" ref="password" name="password" placeholder="Password"
size="24" onChange={this.onChangePassword} value={this.state.password} />
<br />
<input id="password-confirm" type="password" name="password_confirm" placeholder= "Verify Password"
size="24" onChange={this.onChangePasswordConfirm} value={this.state.passwordConfirm} />
<br />
<p>
<button type="submit" className="btn btn-primary">Change</button>
</p>
</form>
</div>
);
}
});
var CreateAdminForm = React.createClass({
propTypes: {
loginAfter: React.PropTypes.bool.isRequired
},
getInitialState: function () {
return this.getStoreState();
},
getStoreState: function () {
return {
username: createAdminStore.getUsername(),
password: createAdminStore.getPassword()
};
},
onChange: function () {
this.setState(this.getStoreState());
},
getDefaultProps: function () {
return {
loginAfter: ''
};
},
onChangeUsername: function (e) {
AuthActions.updateCreateAdminUsername(e.target.value);
},
onChangePassword: function (e) {
AuthActions.updateCreateAdminPassword(e.target.value);
},
componentDidMount: function () {
React.findDOMNode(this.refs.username).focus();
createAdminStore.on('change', this.onChange, this);
},
componentWillUnmount: function () {
createAdminStore.off('change', this.onChange);
},
createAdmin: function (e) {
e.preventDefault();
AuthActions.createAdmin(this.state.username, this.state.password, this.props.loginAfter);
},
render: function () {
return (
<div className="auth-page">
<h3>Create Admins</h3>
<p>
Before a server admin is configured, all clients have admin privileges. This is fine when
HTTP access is restricted to trusted users. <strong>If end-users will be accessing this
CouchDB, you must create an admin account to prevent accidental (or malicious) data
loss.</strong>
</p>
<p>
Server admins can create and destroy databases, install and update _design documents, run
the test suite, and edit all aspects of CouchDB configuration.
</p>
<form id="create-admin-form" onSubmit={this.createAdmin}>
<input id="username" type="text" ref="username" name="name" placeholder="Username" size="24"
onChange={this.onChangeUsername} />
<br/>
<input id="password" type="password" name="password" placeholder= "Password" size="24"
onChange={this.onChangePassword} />
<p>
Non-admin users have read and write access to all databases, which
are controlled by validation functions. CouchDB can be configured to block all
access to anonymous users.
</p>
<button type="submit" id="create-admin" className="btn btn-primary">Create Admin</button>
</form>
</div>
);
}
});
var CreateAdminSidebar = React.createClass({
getInitialState: function () {
return this.getStoreState();
},
getStoreState: function () {
return {
selectedPage: createAdminSidebarStore.getSelectedPage()
};
},
onChange: function () {
this.setState(this.getStoreState());
},
componentDidMount: function () {
createAdminSidebarStore.on('change', this.onChange, this);
},
componentWillUnmount: function () {
createAdminSidebarStore.off('change', this.onChange);
},
selectPage: function (e) {
var newPage = e.target.href.split('#')[1];
AuthActions.selectPage(newPage);
},
render: function () {
var user = FauxtonAPI.session.user();
var userName = _.isNull(user) ? '' : FauxtonAPI.session.user().name;
return (
<div className="sidenav">
<header className="row-fluid">
<h3>{userName}</h3>
</header>
<ul className="nav nav-list" onClick={this.selectPage}>
<li className={this.state.selectedPage === 'changePassword' ? 'active' : ''} data-page="changePassword">
<a href="#changePassword">Change Password</a>
</li>
<li className={this.state.selectedPage === 'addAdmin' ? 'active' : ''} data-page="addAdmin">
<a href="#addAdmin">Create Admins</a>
</li>
</ul>
</div>
);
}
});
return {
LoginForm: LoginForm,
ChangePasswordForm: ChangePasswordForm,
CreateAdminForm: CreateAdminForm,
CreateAdminSidebar: CreateAdminSidebar
};
});