summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2015-12-08 13:38:43 -0500
committerChristopher Speller <crspeller@gmail.com>2015-12-16 17:30:15 -0500
commit58358ddd7cd0152bf16a7326e1d595524fb51246 (patch)
tree350cd462f9b530529e0f098fa1d458c3a36abd4a /web/react/components
parent4f881046bf2a4c74fb44d71e2e78826c70719a8c (diff)
downloadchat-58358ddd7cd0152bf16a7326e1d595524fb51246.tar.gz
chat-58358ddd7cd0152bf16a7326e1d595524fb51246.tar.bz2
chat-58358ddd7cd0152bf16a7326e1d595524fb51246.zip
Some refactoring
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/about_build_modal.jsx8
-rw-r--r--web/react/components/admin_console/admin_controller.jsx3
-rw-r--r--web/react/components/admin_console/admin_sidebar.jsx11
-rw-r--r--web/react/components/admin_console/ldap_settings.jsx388
-rw-r--r--web/react/components/login.jsx146
-rw-r--r--web/react/components/login_email.jsx137
-rw-r--r--web/react/components/login_ldap.jsx110
-rw-r--r--web/react/components/signup_team.jsx7
-rw-r--r--web/react/components/signup_user_complete.jsx14
-rw-r--r--web/react/components/team_signup_choose_auth.jsx18
-rw-r--r--web/react/components/team_signup_with_sso.jsx12
11 files changed, 729 insertions, 125 deletions
diff --git a/web/react/components/about_build_modal.jsx b/web/react/components/about_build_modal.jsx
index 6962876d4..f71e1c9ab 100644
--- a/web/react/components/about_build_modal.jsx
+++ b/web/react/components/about_build_modal.jsx
@@ -33,10 +33,14 @@ export default class AboutBuildModal extends React.Component {
<div className='col-sm-3 info__label'>{'Build Date:'}</div>
<div className='col-sm-9'>{config.BuildDate}</div>
</div>
- <div className='row'>
+ <div className='row form-group'>
<div className='col-sm-3 info__label'>{'Build Hash:'}</div>
<div className='col-sm-9'>{config.BuildHash}</div>
</div>
+ <div className='row'>
+ <div className='col-sm-3 info__label'>{'Enterprise Ready:'}</div>
+ <div className='col-sm-9'>{config.BuildEnterpriseReady}</div>
+ </div>
</Modal.Body>
<Modal.Footer>
<button
@@ -59,4 +63,4 @@ AboutBuildModal.defaultProps = {
AboutBuildModal.propTypes = {
show: React.PropTypes.bool.isRequired,
onModalDismissed: React.PropTypes.func.isRequired
-}; \ No newline at end of file
+};
diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx
index e587c4f84..32b2e9bb7 100644
--- a/web/react/components/admin_console/admin_controller.jsx
+++ b/web/react/components/admin_console/admin_controller.jsx
@@ -21,6 +21,7 @@ import ServiceSettingsTab from './service_settings.jsx';
import LegalAndSupportSettingsTab from './legal_and_support_settings.jsx';
import TeamUsersTab from './team_users.jsx';
import TeamAnalyticsTab from './team_analytics.jsx';
+import LdapSettingsTab from './ldap_settings.jsx';
export default class AdminController extends React.Component {
constructor(props) {
@@ -151,6 +152,8 @@ export default class AdminController extends React.Component {
tab = <ServiceSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'legal_and_support_settings') {
tab = <LegalAndSupportSettingsTab config={this.state.config} />;
+ } else if (this.state.selected === 'ldap_settings') {
+ tab = <LdapSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'team_users') {
if (this.state.teams) {
tab = <TeamUsersTab team={this.state.teams[this.state.selectedTeam]} />;
diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx
index da445da37..587fb35ed 100644
--- a/web/react/components/admin_console/admin_sidebar.jsx
+++ b/web/react/components/admin_console/admin_sidebar.jsx
@@ -255,6 +255,15 @@ export default class AdminSidebar extends React.Component {
<li>
<a
href='#'
+ className={this.isSelected('ldap_settings')}
+ onClick={this.handleClick.bind(this, 'ldap_settings', null)}
+ >
+ {'LDAP Settings'}
+ </a>
+ </li>
+ <li>
+ <a
+ href='#'
className={this.isSelected('legal_and_support_settings')}
onClick={this.handleClick.bind(this, 'legal_and_support_settings', null)}
>
@@ -334,4 +343,4 @@ AdminSidebar.propTypes = {
selected: React.PropTypes.string,
selectedTeam: React.PropTypes.string,
selectTab: React.PropTypes.func
-}; \ No newline at end of file
+};
diff --git a/web/react/components/admin_console/ldap_settings.jsx b/web/react/components/admin_console/ldap_settings.jsx
new file mode 100644
index 000000000..f8ea62192
--- /dev/null
+++ b/web/react/components/admin_console/ldap_settings.jsx
@@ -0,0 +1,388 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import * as Client from '../../utils/client.jsx';
+import * as AsyncClient from '../../utils/async_client.jsx';
+
+const DEFAULT_LDAP_PORT = 389;
+const DEFAULT_QUERY_TIMEOUT = 60;
+
+export default class LdapSettings extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.handleEnable = this.handleEnable.bind(this);
+ this.handleDisable = this.handleDisable.bind(this);
+
+ this.state = {
+ saveNeeded: false,
+ serverError: null,
+ enable: this.props.config.LdapSettings.Enable
+ };
+ }
+ handleChange() {
+ this.setState({saveNeeded: true});
+ }
+ handleEnable() {
+ this.setState({saveNeeded: true, enable: true});
+ }
+ handleDisable() {
+ this.setState({saveNeeded: true, enable: false});
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+ $('#save-button').button('loading');
+
+ const config = this.props.config;
+ config.LdapSettings.Enable = this.refs.Enable.checked;
+ config.LdapSettings.LdapServer = this.refs.LdapServer.value.trim();
+
+ let LdapPort = DEFAULT_LDAP_PORT;
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.LdapPort).value, 10))) {
+ LdapPort = parseInt(ReactDOM.findDOMNode(this.refs.LdapPort).value, 10);
+ }
+ config.LdapSettings.LdapPort = LdapPort;
+
+ config.LdapSettings.BaseDN = this.refs.BaseDN.value.trim();
+ config.LdapSettings.BindUsername = this.refs.BindUsername.value.trim();
+ config.LdapSettings.BindPassword = this.refs.BindPassword.value.trim();
+ config.LdapSettings.FirstNameAttribute = this.refs.FirstNameAttribute.value.trim();
+ config.LdapSettings.LastNameAttribute = this.refs.LastNameAttribute.value.trim();
+ config.LdapSettings.EmailAttribute = this.refs.EmailAttribute.value.trim();
+ config.LdapSettings.UsernameAttribute = this.refs.UsernameAttribute.value.trim();
+ config.LdapSettings.IdAttribute = this.refs.IdAttribute.value.trim();
+
+ let QueryTimeout = DEFAULT_QUERY_TIMEOUT;
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.QueryTimeout).value, 10))) {
+ QueryTimeout = parseInt(ReactDOM.findDOMNode(this.refs.QueryTimeout).value, 10);
+ }
+ config.LdapSettings.QueryTimeout = QueryTimeout;
+
+ Client.saveConfig(
+ config,
+ () => {
+ AsyncClient.getConfig();
+ this.setState({
+ serverError: null,
+ saveNeeded: false
+ });
+ $('#save-button').button('reset');
+ },
+ (err) => {
+ this.setState({
+ serverError: err.message,
+ saveNeeded: true
+ });
+ $('#save-button').button('reset');
+ }
+ );
+ }
+ render() {
+ let serverError = '';
+ if (this.state.serverError) {
+ serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
+ }
+
+ let saveClass = 'btn';
+ if (this.state.saveNeeded) {
+ saveClass = 'btn btn-primary';
+ }
+
+ return (
+ <div className='wrapper--fixed'>
+ <h3>{'LDAP Settings'}</h3>
+ <form
+ className='form-horizontal'
+ role='form'
+ >
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='Enable'
+ >
+ {'Enable Login With LDAP:'}
+ </label>
+ <div className='col-sm-8'>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='Enable'
+ value='true'
+ ref='Enable'
+ defaultChecked={this.props.config.LdapSettings.Enable}
+ onChange={this.handleEnable}
+ />
+ {'true'}
+ </label>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='Enable'
+ value='false'
+ defaultChecked={!this.props.config.LdapSettings.Enable}
+ onChange={this.handleDisable}
+ />
+ {'false'}
+ </label>
+ <p className='help-text'>{'When true, Mattermost allows login using LDAP'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='LdapServer'
+ >
+ {'LDAP Server:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='LdapServer'
+ ref='LdapServer'
+ placeholder='Ex "10.0.0.23"'
+ defaultValue={this.props.config.LdapSettings.LdapServer}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The domain or ip address of LDAP server.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='LdapPort'
+ >
+ {'LDAP Port:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='number'
+ className='form-control'
+ id='LdapPort'
+ ref='LdapPort'
+ placeholder='Ex "389"'
+ defaultValue={this.props.config.LdapSettings.LdapPort}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The port to connect to the LDAP server on. Default is 389.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='BaseDN'
+ >
+ {'BaseDN:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='BaseDN'
+ ref='BaseDN'
+ placeholder='Ex "dc=mydomain,dc=com"'
+ defaultValue={this.props.config.LdapSettings.BaseDN}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The base dn where mattermost should search for users.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='BindUsername'
+ >
+ {'Bind Username:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='BindUsername'
+ ref='BindUsername'
+ placeholder=''
+ defaultValue={this.props.config.LdapSettings.BindUsername}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'Username of a user with read access to the LDAP server specified.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='BindPassword'
+ >
+ {'Bind Password:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='password'
+ className='form-control'
+ id='BindPassword'
+ ref='BindPassword'
+ placeholder=''
+ defaultValue={this.props.config.LdapSettings.BindPassword}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'Password of the user given above.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='FirstNameAttribute'
+ >
+ {'First Name Attrubute'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='FirstNameAttribute'
+ ref='FirstNameAttribute'
+ placeholder='Ex "givenName"'
+ defaultValue={this.props.config.LdapSettings.FirstNameAttribute}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The first name attribute of entires in the LDAP server.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='LastNameAttribute'
+ >
+ {'Last Name Attribute:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='LastNameAttribute'
+ ref='LastNameAttribute'
+ placeholder='Ex "sn"'
+ defaultValue={this.props.config.LdapSettings.LastNameAttribute}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The last name attribute of entries in the LDAP server.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='EmailAttribute'
+ >
+ {'Email Attribute:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='EmailAttribute'
+ ref='EmailAttribute'
+ placeholder='Ex "mail"'
+ defaultValue={this.props.config.LdapSettings.EmailAttribute}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The email attribute of entries in the LDAP server.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='UsernameAttribute'
+ >
+ {'Username Attribute:'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='UsernameAttribute'
+ ref='UsernameAttribute'
+ placeholder='Ex "sAMAccountName"'
+ defaultValue={this.props.config.LdapSettings.UsernameAttribute}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The attribute of entries in the LDAP server to use for username in Mattermost. May be the same as the ID Attribute.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='IdAttribute'
+ >
+ {'Id Attribute: '}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='IdAttribute'
+ ref='IdAttribute'
+ placeholder='Ex "sAMAccountName"'
+ defaultValue={this.props.config.LdapSettings.IdAttribute}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The attribute of entries in the LDAP server to use as a unique identifier. Users will use this to login. Ideally this would be the username they are used to loging in with. May be the same as the username attribute above.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
+ htmlFor='QueryTimeout'
+ >
+ {'Query Timeout (seconds):'}
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='number'
+ className='form-control'
+ id='QueryTimeout'
+ ref='QueryTimeout'
+ placeholder='Ex "60"'
+ defaultValue={this.props.config.LdapSettings.QueryTimeout}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>{'The timeout value for queries to the LDAP server. Increase if you are getting timeout errors caused by a slow LDAP server.'}</p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <div className='col-sm-12'>
+ {serverError}
+ <button
+ disabled={!this.state.saveNeeded}
+ type='submit'
+ className={saveClass}
+ onClick={this.handleSubmit}
+ id='save-button'
+ data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Saving Config...'}
+ >
+ {'Save'}
+ </button>
+ </div>
+ </div>
+ </form>
+ </div>
+ );
+ }
+}
+LdapSettings.defaultProps = {
+};
+
+LdapSettings.propTypes = {
+ config: React.PropTypes.object
+};
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index d87bd20ad..9afaa8b0d 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -2,97 +2,19 @@
// See License.txt for license information.
import * as Utils from '../utils/utils.jsx';
-import * as Client from '../utils/client.jsx';
-import UserStore from '../stores/user_store.jsx';
-import BrowserStore from '../stores/browser_store.jsx';
+import LoginEmail from './login_email.jsx';
+import LoginLdap from './login_ldap.jsx';
export default class Login extends React.Component {
constructor(props) {
super(props);
- this.handleSubmit = this.handleSubmit.bind(this);
-
this.state = {};
}
- handleSubmit(e) {
- e.preventDefault();
- var state = {};
-
- const name = this.props.teamName;
- if (!name) {
- state.serverError = 'Bad team name';
- this.setState(state);
- return;
- }
-
- const email = ReactDOM.findDOMNode(this.refs.email).value.trim();
- if (!email) {
- state.serverError = 'An email is required';
- this.setState(state);
- return;
- }
-
- const password = ReactDOM.findDOMNode(this.refs.password).value.trim();
- if (!password) {
- state.serverError = 'A password is required';
- this.setState(state);
- return;
- }
-
- if (!BrowserStore.isLocalStorageSupported()) {
- state.serverError = 'This service requires local storage to be enabled. Please enable it or exit private browsing.';
- this.setState(state);
- return;
- }
-
- state.serverError = '';
- this.setState(state);
-
- Client.loginByEmail(name, email, password,
- () => {
- UserStore.setLastEmail(email);
-
- const redirect = Utils.getUrlParameter('redirect');
- if (redirect) {
- window.location.href = decodeURIComponent(redirect);
- } else {
- window.location.href = '/' + name + '/channels/town-square';
- }
- },
- (err) => {
- if (err.message === 'Login failed because email address has not been verified') {
- window.location.href = '/verify_email?teamname=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
- return;
- }
- state.serverError = err.message;
- this.valid = false;
- this.setState(state);
- }
- );
- }
render() {
- let serverError;
- if (this.state.serverError) {
- serverError = <label className='control-label'>{this.state.serverError}</label>;
- }
- let priorEmail = UserStore.getLastEmail();
-
- const emailParam = Utils.getUrlParameter('email');
- if (emailParam) {
- priorEmail = decodeURIComponent(emailParam);
- }
-
const teamDisplayName = this.props.teamDisplayName;
const teamName = this.props.teamName;
- let focusEmail = false;
- let focusPassword = false;
- if (priorEmail === '') {
- focusEmail = true;
- } else {
- focusPassword = true;
- }
-
let loginMessage = [];
if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
loginMessage.push(
@@ -106,9 +28,16 @@ export default class Login extends React.Component {
);
}
- let errorClass = '';
- if (serverError) {
- errorClass = ' has-error';
+ if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
+ loginMessage.push(
+ <a
+ className='btn btn-custom-login google'
+ href={'/' + teamName + '/login/google'}
+ >
+ <span className='icon' />
+ <span>{'with Google Apps'}</span>
+ </a>
+ );
}
const verifiedParam = Utils.getUrlParameter('verified');
@@ -125,39 +54,9 @@ export default class Login extends React.Component {
let emailSignup;
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
emailSignup = (
- <div className='signup__email-container'>
- <div className={'form-group' + errorClass}>
- <input
- autoFocus={focusEmail}
- type='email'
- className='form-control'
- name='email'
- defaultValue={priorEmail}
- ref='email'
- placeholder='Email'
- spellCheck='false'
- />
- </div>
- <div className={'form-group' + errorClass}>
- <input
- autoFocus={focusPassword}
- type='password'
- className='form-control'
- name='password'
- ref='password'
- placeholder='Password'
- spellCheck='false'
- />
- </div>
- <div className='form-group'>
- <button
- type='submit'
- className='btn btn-primary'
- >
- {'Sign in'}
- </button>
- </div>
- </div>
+ <LoginEmail
+ teamName={this.props.teamName}
+ />
);
}
@@ -211,25 +110,30 @@ export default class Login extends React.Component {
);
}
+ let ldapLogin = null;
+ if (global.window.mm_config.EnableLdap === 'true') {
+ ldapLogin = (
+ <LoginLdap
+ teamName={this.props.teamName}
+ />
+ );
+ }
+
return (
<div className='signup-team__container'>
<h5 className='margin--less'>{'Sign in to:'}</h5>
<h2 className='signup-team__name'>{teamDisplayName}</h2>
<h2 className='signup-team__subdomain'>{'on '}{global.window.mm_config.SiteName}</h2>
- <form onSubmit={this.handleSubmit}>
{verifiedBox}
- <div className={'form-group' + errorClass}>
- {serverError}
- </div>
{loginMessage}
{emailSignup}
+ {ldapLogin}
{userSignUp}
<div className='form-group margin--extra form-group--small'>
<span><a href='/find_team'>{'Find your other teams'}</a></span>
</div>
{forgotPassword}
{teamSignUp}
- </form>
</div>
);
}
diff --git a/web/react/components/login_email.jsx b/web/react/components/login_email.jsx
new file mode 100644
index 000000000..cfe34d1c7
--- /dev/null
+++ b/web/react/components/login_email.jsx
@@ -0,0 +1,137 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import * as Utils from '../utils/utils.jsx';
+import * as Client from '../utils/client.jsx';
+import UserStore from '../stores/user_store.jsx';
+
+export default class LoginEmail extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+
+ this.state = {
+ serverError: ''
+ };
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+ var state = {};
+
+ const name = this.props.teamName;
+ if (!name) {
+ state.serverError = 'Bad team name';
+ this.setState(state);
+ return;
+ }
+
+ const email = this.refs.email.value.trim();
+ if (!email) {
+ state.serverError = 'An email is required';
+ this.setState(state);
+ return;
+ }
+
+ const password = this.refs.password.value.trim();
+ if (!password) {
+ state.serverError = 'A password is required';
+ this.setState(state);
+ return;
+ }
+
+ state.serverError = '';
+ this.setState(state);
+
+ Client.loginByEmail(name, email, password,
+ () => {
+ UserStore.setLastEmail(email);
+
+ const redirect = Utils.getUrlParameter('redirect');
+ if (redirect) {
+ window.location.href = decodeURIComponent(redirect);
+ } else {
+ window.location.href = '/' + name + '/channels/town-square';
+ }
+ },
+ (err) => {
+ if (err.message === 'Login failed because email address has not been verified') {
+ window.location.href = '/verify_email?teamname=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
+ return;
+ }
+ state.serverError = err.message;
+ this.valid = false;
+ this.setState(state);
+ }
+ );
+ }
+ render() {
+ let serverError;
+ let errorClass = '';
+ if (this.state.serverError) {
+ serverError = <label className='control-label'>{this.state.serverError}</label>;
+ errorClass = ' has-error';
+ }
+
+ let priorEmail = UserStore.getLastEmail();
+ let focusEmail = false;
+ let focusPassword = false;
+ if (priorEmail === '') {
+ focusEmail = true;
+ } else {
+ focusPassword = true;
+ }
+
+ const emailParam = Utils.getUrlParameter('email');
+ if (emailParam) {
+ priorEmail = decodeURIComponent(emailParam);
+ }
+
+ return (
+ <form onSubmit={this.handleSubmit}>
+ <div className='signup__email-container'>
+ <div className={'form-group' + errorClass}>
+ {serverError}
+ </div>
+ <div className={'form-group' + errorClass}>
+ <input
+ autoFocus={focusEmail}
+ type='email'
+ className='form-control'
+ name='email'
+ defaultValue={priorEmail}
+ ref='email'
+ placeholder='Email'
+ spellCheck='false'
+ />
+ </div>
+ <div className={'form-group' + errorClass}>
+ <input
+ autoFocus={focusPassword}
+ type='password'
+ className='form-control'
+ name='password'
+ ref='password'
+ placeholder='Password'
+ spellCheck='false'
+ />
+ </div>
+ <div className='form-group'>
+ <button
+ type='submit'
+ className='btn btn-primary'
+ >
+ {'Sign in'}
+ </button>
+ </div>
+ </div>
+ </form>
+ );
+ }
+}
+LoginEmail.defaultProps = {
+};
+
+LoginEmail.propTypes = {
+ teamName: React.PropTypes.string.isRequired
+};
diff --git a/web/react/components/login_ldap.jsx b/web/react/components/login_ldap.jsx
new file mode 100644
index 000000000..1e0e32f4f
--- /dev/null
+++ b/web/react/components/login_ldap.jsx
@@ -0,0 +1,110 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import * as Utils from '../utils/utils.jsx';
+import * as Client from '../utils/client.jsx';
+
+export default class LoginLdap extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+
+ this.state = {
+ serverError: ''
+ };
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+ var state = {};
+
+ const teamName = this.props.teamName;
+ if (!teamName) {
+ state.serverError = 'Bad team name';
+ this.setState(state);
+ return;
+ }
+
+ const id = this.refs.id.value.trim();
+ if (!id) {
+ state.serverError = 'An LDAP ID is required';
+ this.setState(state);
+ return;
+ }
+
+ const password = this.refs.password.value.trim();
+ if (!password) {
+ state.serverError = 'An LDAP password is required';
+ this.setState(state);
+ return;
+ }
+
+ state.serverError = '';
+ this.setState(state);
+
+ Client.loginByLdap(teamName, id, password,
+ () => {
+ const redirect = Utils.getUrlParameter('redirect');
+ if (redirect) {
+ window.location.href = decodeURIComponent(redirect);
+ } else {
+ window.location.href = '/' + teamName + '/channels/town-square';
+ }
+ },
+ (err) => {
+ state.serverError = err.message;
+ this.setState(state);
+ }
+ );
+ }
+ render() {
+ let serverError;
+ let errorClass = '';
+ if (this.state.serverError) {
+ serverError = <label className='control-label'>{this.state.serverError}</label>;
+ errorClass = ' has-error';
+ }
+
+ return (
+ <form onSubmit={this.handleSubmit}>
+ <div className='signup__email-container'>
+ <div className={'form-group' + errorClass}>
+ {serverError}
+ </div>
+ <div className={'form-group' + errorClass}>
+ <input
+ autoFocus={true}
+ className='form-control'
+ ref='id'
+ placeholder='LDAP Username'
+ spellCheck='false'
+ />
+ </div>
+ <div className={'form-group' + errorClass}>
+ <input
+ type='password'
+ className='form-control'
+ ref='password'
+ placeholder='LDAP Password'
+ spellCheck='false'
+ />
+ </div>
+ <div className='form-group'>
+ <button
+ type='submit'
+ className='btn btn-primary'
+ >
+ {'Sign in'}
+ </button>
+ </div>
+ </div>
+ </form>
+ );
+ }
+}
+LoginLdap.defaultProps = {
+};
+
+LoginLdap.propTypes = {
+ teamName: React.PropTypes.string.isRequired
+};
diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx
index 0ac837326..0e05bc533 100644
--- a/web/react/components/signup_team.jsx
+++ b/web/react/components/signup_team.jsx
@@ -112,6 +112,13 @@ export default class TeamSignUp extends React.Component {
<SSOSignupPage service={Constants.GITLAB_SERVICE} />
</div>
);
+ } else if (this.state.page === 'google') {
+ return (
+ <div>
+ {teamListing}
+ <SSOSignupPage service={Constants.GOOGLE_SERVICE} />
+ </div>
+ );
}
}
}
diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index 2bde78726..df11fe045 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -183,11 +183,23 @@ export default class SignupUserComplete extends React.Component {
href={'/' + this.props.teamName + '/signup/gitlab' + window.location.search}
>
<span className='icon' />
- <span>with GitLab</span>
+ <span>{'with GitLab'}</span>
</a>
);
}
+ if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
+ signupMessage.push(
+ <a
+ className='btn btn-custom-login google'
+ href={'/' + this.props.teamName + '/signup/google' + window.location.search}
+ >
+ <span className='icon' />
+ <span>{'with Google'}</span>
+ </a>
+ );
+ }
+
var emailSignup;
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
emailSignup = (
diff --git a/web/react/components/team_signup_choose_auth.jsx b/web/react/components/team_signup_choose_auth.jsx
index 0254c8b4e..19b9750b3 100644
--- a/web/react/components/team_signup_choose_auth.jsx
+++ b/web/react/components/team_signup_choose_auth.jsx
@@ -26,6 +26,24 @@ export default class ChooseAuthPage extends React.Component {
);
}
+ if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
+ buttons.push(
+ <a
+ className='btn btn-custom-login google btn-full'
+ href='#'
+ onClick={
+ (e) => {
+ e.preventDefault();
+ this.props.updatePage('google');
+ }
+ }
+ >
+ <span className='icon' />
+ <span>{'Create new team with Google Apps Account'}</span>
+ </a>
+ );
+ }
+
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
buttons.push(
<a
diff --git a/web/react/components/team_signup_with_sso.jsx b/web/react/components/team_signup_with_sso.jsx
index e3f16efb0..f4b323956 100644
--- a/web/react/components/team_signup_with_sso.jsx
+++ b/web/react/components/team_signup_with_sso.jsx
@@ -88,6 +88,18 @@ export default class SSOSignUpPage extends React.Component {
<span>{'Create team with GitLab Account'}</span>
</a>
);
+ } else if (this.props.service === Constants.GOOGLE_SERVICE) {
+ button = (
+ <a
+ className='btn btn-custom-login google btn-full'
+ href='#'
+ onClick={this.handleSubmit}
+ disabled={disabled}
+ >
+ <span className='icon'/>
+ <span>{'Create team with Google Apps Account'}</span>
+ </a>
+ );
}
return (