summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2015-08-28 09:14:37 -0400
committerChristopher Speller <crspeller@gmail.com>2015-08-28 09:14:37 -0400
commit75af5d4536cc414d171c2fe6dca78e455eb18b37 (patch)
tree4e00cf97b5f4f570b1901093bfa4e208749932a0 /web/react/components
parentd107b392a6309a41eac6cd7d07d720a21968eb56 (diff)
parentf5fec3a157e6c9146a0c4e28dd5f70e6c066affd (diff)
downloadchat-75af5d4536cc414d171c2fe6dca78e455eb18b37.tar.gz
chat-75af5d4536cc414d171c2fe6dca78e455eb18b37.tar.bz2
chat-75af5d4536cc414d171c2fe6dca78e455eb18b37.zip
Merge pull request #496 from mattermost/mm-2015
MM-2015 Added the ability to create a team with SSO services and added the ability to turn off email sign up.
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/login.jsx80
-rw-r--r--web/react/components/signup_team.jsx106
-rw-r--r--web/react/components/signup_user_complete.jsx51
-rw-r--r--web/react/components/signup_user_oauth.jsx87
-rw-r--r--web/react/components/team_signup_choose_auth.jsx88
-rw-r--r--web/react/components/team_signup_with_email.jsx82
-rw-r--r--web/react/components/team_signup_with_sso.jsx137
7 files changed, 438 insertions, 193 deletions
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index 678a2ff87..489ff6960 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -10,7 +10,9 @@ var Constants = require('../utils/constants.jsx');
export default class Login extends React.Component {
constructor(props) {
super(props);
+
this.handleSubmit = this.handleSubmit.bind(this);
+
this.state = {};
}
handleSubmit(e) {
@@ -96,19 +98,28 @@ export default class Login extends React.Component {
var authServices = JSON.parse(this.props.authServices);
var loginMessage = [];
- if (authServices.indexOf(Constants.GITLAB_SERVICE) >= 0) {
+ if (authServices.indexOf(Constants.GITLAB_SERVICE) !== -1) {
loginMessage.push(
- <div className='form-group form-group--small'>
- <span><a href={'/' + teamName + '/login/gitlab'}>{'Log in with GitLab'}</a></span>
- </div>
- );
+ <a
+ className='btn btn-custom-login gitlab'
+ href={'/' + teamName + '/login/gitlab'}
+ >
+ <span className='icon' />
+ <span>with GitLab</span>
+ </a>
+ );
}
- if (authServices.indexOf(Constants.GOOGLE_SERVICE) >= 0) {
+
+ if (authServices.indexOf(Constants.GOOGLE_SERVICE) !== -1) {
loginMessage.push(
- <div className='form-group form-group--small'>
- <span><a href={'/' + teamName + '/login/google'}>{'Log in with Google'}</a></span>
- </div>
- );
+ <a
+ className='btn btn-custom-login google'
+ href={'/' + teamName + '/login/google'}
+ >
+ <span className='icon' />
+ <span>with Google Apps</span>
+ </a>
+ );
}
var errorClass = '';
@@ -116,15 +127,10 @@ export default class Login extends React.Component {
errorClass = ' has-error';
}
- 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 {config.SiteName}</h2>
- <form onSubmit={this.handleSubmit}>
- <div className={'form-group' + errorClass}>
- {serverError}
- </div>
+ var emailSignup;
+ if (authServices.indexOf(Constants.EMAIL_SERVICE) !== -1) {
+ emailSignup = (
+ <div>
<div className={'form-group' + errorClass}>
<input
autoFocus={focusEmail}
@@ -154,13 +160,43 @@ export default class Login extends React.Component {
Sign in
</button>
</div>
+ </div>
+ );
+ }
+
+ var forgotPassword;
+ if (loginMessage.length > 0 && emailSignup) {
+ loginMessage = (
+ <div>
+ {loginMessage}
+ <div className='or__container'>
+ <span>or</span>
+ </div>
+ </div>
+ );
+
+ forgotPassword = (
+ <div className='form-group'>
+ <a href={'/' + teamName + '/reset_password'}>I forgot my password</a>
+ </div>
+ );
+ }
+
+ 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 {config.SiteName}</h2>
+ <form onSubmit={this.handleSubmit}>
+ <div className={'form-group' + errorClass}>
+ {serverError}
+ </div>
{loginMessage}
+ {emailSignup}
<div className='form-group margin--extra form-group--small'>
<span><a href='/find_team'>{'Find other ' + strings.TeamPlural}</a></span>
</div>
- <div className='form-group'>
- <a href={'/' + teamName + '/reset_password'}>I forgot my password</a>
- </div>
+ {forgotPassword}
<div className='margin--extra'>
<span>{'Want to create your own ' + strings.Team + '? '}
<a
diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx
index edd48e0b9..13640b1e5 100644
--- a/web/react/components/signup_team.jsx
+++ b/web/react/components/signup_team.jsx
@@ -1,69 +1,49 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-
-var utils = require('../utils/utils.jsx');
-var client = require('../utils/client.jsx');
-
-module.exports = React.createClass({
- handleSubmit: function(e) {
- e.preventDefault();
- var team = {};
- var state = { server_error: "" };
-
- team.email = this.refs.email.getDOMNode().value.trim().toLowerCase();
- if (!team.email || !utils.isEmail(team.email)) {
- state.email_error = "Please enter a valid email address";
- state.inValid = true;
+var ChoosePage = require('./team_signup_choose_auth.jsx');
+var EmailSignUpPage = require('./team_signup_with_email.jsx');
+var SSOSignupPage = require('./team_signup_with_sso.jsx');
+var Constants = require('../utils/constants.jsx');
+
+export default class TeamSignUp extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.updatePage = this.updatePage.bind(this);
+
+ if (props.services.length === 1) {
+ if (props.services[0] === Constants.EMAIL_SERVICE) {
+ this.state = {page: 'email', service: ''};
+ } else {
+ this.state = {page: 'service', service: props.services[0]};
+ }
+ } else {
+ this.state = {page: 'choose', service: ''};
}
- else {
- state.email_error = "";
- }
-
- if (state.inValid) {
- this.setState(state);
- return;
+ }
+ updatePage(page, service) {
+ this.setState({page: page, service: service});
+ }
+ render() {
+ if (this.state.page === 'email') {
+ return <EmailSignUpPage />;
+ } else if (this.state.page === 'service' && this.state.service !== '') {
+ return <SSOSignupPage service={this.state.service} />;
+ } else {
+ return (
+ <ChoosePage
+ services={this.props.services}
+ updatePage={this.updatePage}
+ />
+ );
}
-
- client.signupTeam(team.email,
- function(data) {
- if (data["follow_link"]) {
- window.location.href = data["follow_link"];
- }
- else {
- window.location.href = "/signup_team_confirm/?email=" + encodeURIComponent(team.email);
- }
- }.bind(this),
- function(err) {
- state.server_error = err.message;
- this.setState(state);
- }.bind(this)
- );
- },
- getInitialState: function() {
- return { };
- },
- render: function() {
-
- var email_error = this.state.email_error ? <label className='control-label'>{ this.state.email_error }</label> : null;
- var server_error = this.state.server_error ? <div className={ "form-group has-error" }><label className='control-label'>{ this.state.server_error }</label></div> : null;
-
- return (
- <form role="form" onSubmit={this.handleSubmit}>
- <div className={ email_error ? "form-group has-error" : "form-group" }>
- <input autoFocus={true} type="email" ref="email" className="form-control" placeholder="Email Address" maxLength="128" />
- { email_error }
- </div>
- { server_error }
- <div className="form-group">
- <button className="btn btn-md btn-primary" type="submit">Sign up</button>
- </div>
- <div className="form-group margin--extra-2x">
- <span><a href="/find_team">{"Find my " + strings.Team}</a></span>
- </div>
- </form>
- );
}
-});
-
-
+}
+
+TeamSignUp.defaultProps = {
+ services: []
+};
+TeamSignUp.propTypes = {
+ services: React.PropTypes.array
+};
diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index 0393e0413..e5c602c16 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -171,7 +171,35 @@ module.exports = React.createClass({
);
}
- if (signupMessage.length > 0) {
+ var emailSignup;
+ if (authServices.indexOf(Constants.EMAIL_SERVICE) !== -1) {
+ emailSignup = (
+ <div>
+ <div className='inner__content'>
+ {email}
+ {yourEmailIs}
+ <div className='margin--extra'>
+ <h5><strong>Choose your username</strong></h5>
+ <div className={nameDivStyle}>
+ <input type='text' ref='name' className='form-control' placeholder='' maxLength='128' />
+ {nameError}
+ <p className='form__hint'>Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'</p>
+ </div>
+ </div>
+ <div className='margin--extra'>
+ <h5><strong>Choose your password</strong></h5>
+ <div className={passwordDivStyle}>
+ <input type='password' ref='password' className='form-control' placeholder='' maxLength='128' />
+ {passwordError}
+ </div>
+ </div>
+ </div>
+ <p className='margin--extra'><button type='submit' onClick={this.handleSubmit} className='btn-primary btn'>Create Account</button></p>
+ </div>
+ );
+ }
+
+ if (signupMessage.length > 0 && emailSignup) {
signupMessage = (
<div>
{signupMessage}
@@ -196,26 +224,7 @@ module.exports = React.createClass({
<h2 className='signup-team__subdomain'>on {config.SiteName}</h2>
<h4 className='color--light'>Let's create your account</h4>
{signupMessage}
- <div className='inner__content'>
- {email}
- {yourEmailIs}
- <div className='margin--extra'>
- <h5><strong>Choose your username</strong></h5>
- <div className={nameDivStyle}>
- <input type='text' ref='name' className='form-control' placeholder='' maxLength='128' />
- {nameError}
- <p className='form__hint'>Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'</p>
- </div>
- </div>
- <div className='margin--extra'>
- <h5><strong>Choose your password</strong></h5>
- <div className={passwordDivStyle}>
- <input type='password' ref='password' className='form-control' placeholder='' maxLength='128' />
- {passwordError}
- </div>
- </div>
- </div>
- <p className='margin--extra'><button type='submit' onClick={this.handleSubmit} className='btn-primary btn'>Create Account</button></p>
+ {emailSignup}
{serverError}
{termsDisclaimer}
</form>
diff --git a/web/react/components/signup_user_oauth.jsx b/web/react/components/signup_user_oauth.jsx
deleted file mode 100644
index 8b2800bde..000000000
--- a/web/react/components/signup_user_oauth.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-
-var utils = require('../utils/utils.jsx');
-var client = require('../utils/client.jsx');
-var UserStore = require('../stores/user_store.jsx');
-var BrowserStore = require('../stores/browser_store.jsx');
-
-module.exports = React.createClass({
- handleSubmit: function(e) {
- e.preventDefault();
-
- if (!this.state.user.username) {
- this.setState({name_error: "This field is required", email_error: "", password_error: "", server_error: ""});
- return;
- }
-
- var username_error = utils.isValidUsername(this.state.user.username);
- if (username_error === "Cannot use a reserved word as a username.") {
- this.setState({name_error: "This username is reserved, please choose a new one.", email_error: "", password_error: "", server_error: ""});
- return;
- } else if (username_error) {
- this.setState({name_error: "Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", email_error: "", password_error: "", server_error: ""});
- return;
- }
-
- this.setState({name_error: "", server_error: ""});
-
- this.state.user.allow_marketing = this.refs.email_service.getDOMNode().checked;
-
- var user = this.state.user;
- client.createUser(user, "", "",
- function(data) {
- client.track('signup', 'signup_user_oauth_02');
- UserStore.setCurrentUser(data);
- UserStore.setLastEmail(data.email);
-
- window.location.href = '/' + this.props.teamName + '/login/' + user.auth_service + '?login_hint=' + user.email;
- }.bind(this),
- function(err) {
- this.state.server_error = err.message;
- this.setState(this.state);
- }.bind(this)
- );
- },
- handleChange: function() {
- var user = this.state.user;
- user.username = this.refs.name.getDOMNode().value;
- this.setState({ user: user });
- },
- getInitialState: function() {
- var user = JSON.parse(this.props.user);
- return { user: user };
- },
- render: function() {
-
- client.track('signup', 'signup_user_oauth_01');
-
- var name_error = this.state.name_error ? <label className='control-label'>{ this.state.name_error }</label> : null;
- var server_error = this.state.server_error ? <div className={ "form-group has-error" }><label className='control-label'>{ this.state.server_error }</label></div> : null;
-
- var yourEmailIs = this.state.user.email == "" ? "" : <span>Your email address is <b>{ this.state.user.email }.</b></span>;
-
- return (
- <div>
- <img className="signup-team-logo" src="/static/images/logo.png" />
- <h4>Welcome to { config.SiteName }</h4>
- <p>{"To continue signing up with " + this.state.user.auth_service + ", please register a username."}</p>
- <p>Your username can be made of lowercase letters and numbers.</p>
- <label className="control-label">Username</label>
- <div className={ name_error ? "form-group has-error" : "form-group" }>
- <input type="text" ref="name" className="form-control" placeholder="" maxLength="128" value={this.state.user.username} onChange={this.handleChange} />
- { name_error }
- </div>
- <p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others."}</p>
- <p>{ yourEmailIs } You’ll use this address to sign in to {config.SiteName}.</p>
- <div className="checkbox"><label><input type="checkbox" ref="email_service" /> It's ok to send me occassional email with updates about the {config.SiteName} service. </label></div>
- <p><button onClick={this.handleSubmit} className="btn-primary btn">Create Account</button></p>
- { server_error }
- <p>By proceeding to create your account and use { config.SiteName }, you agree to our <a href={ config.TermsLink }>Terms of Service</a> and <a href={ config.PrivacyLink }>Privacy Policy</a>. If you do not agree, you cannot use {config.SiteName}.</p>
- </div>
- );
- }
-});
-
-
diff --git a/web/react/components/team_signup_choose_auth.jsx b/web/react/components/team_signup_choose_auth.jsx
new file mode 100644
index 000000000..2d35785c2
--- /dev/null
+++ b/web/react/components/team_signup_choose_auth.jsx
@@ -0,0 +1,88 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Constants = require('../utils/constants.jsx');
+
+export default class ChooseAuthPage extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+ render() {
+ var buttons = [];
+ if (this.props.services.indexOf(Constants.GITLAB_SERVICE) !== -1) {
+ buttons.push(
+ <a
+ className='btn btn-custom-login gitlab btn-full'
+ href='#'
+ onClick={
+ function clickGit(e) {
+ e.preventDefault();
+ this.props.updatePage('service', Constants.GITLAB_SERVICE);
+ }.bind(this)
+ }
+ >
+ <span className='icon' />
+ <span>Create new {strings.Team} with GitLab Account</span>
+ </a>
+ );
+ }
+
+ if (this.props.services.indexOf(Constants.GOOGLE_SERVICE) !== -1) {
+ buttons.push(
+ <a
+ className='btn btn-custom-login google btn-full'
+ href='#'
+ onClick={
+ function clickGoogle(e) {
+ e.preventDefault();
+ this.props.updatePage('service', Constants.GOOGLE_SERVICE);
+ }.bind(this)
+ }
+ >
+ <span className='icon' />
+ <span>Create new {strings.Team} with Google Apps Account</span>
+ </a>
+ );
+ }
+
+ if (this.props.services.indexOf(Constants.EMAIL_SERVICE) !== -1) {
+ buttons.push(
+ <a
+ className='btn btn-custom-login email btn-full'
+ href='#'
+ onClick={
+ function clickEmail(e) {
+ e.preventDefault();
+ this.props.updatePage('email', '');
+ }.bind(this)
+ }
+ >
+ <span className='fa fa-envelope' />
+ <span>Create new {strings.Team} with email address</span>
+ </a>
+ );
+ }
+
+ if (buttons.length === 0) {
+ buttons = <span>No sign-up methods configured, please contact your system administrator.</span>;
+ }
+
+ return (
+ <div>
+ {buttons}
+ <div className='form-group margin--extra-2x'>
+ <span><a href='/find_team'>{'Find my ' + strings.Team}</a></span>
+ </div>
+ </div>
+ );
+ }
+}
+
+ChooseAuthPage.defaultProps = {
+ services: []
+};
+ChooseAuthPage.propTypes = {
+ services: React.PropTypes.array,
+ updatePage: React.PropTypes.func
+};
diff --git a/web/react/components/team_signup_with_email.jsx b/web/react/components/team_signup_with_email.jsx
new file mode 100644
index 000000000..c7204880f
--- /dev/null
+++ b/web/react/components/team_signup_with_email.jsx
@@ -0,0 +1,82 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var utils = require('../utils/utils.jsx');
+var client = require('../utils/client.jsx');
+
+export default class EmailSignUpPage extends React.Component {
+ constructor() {
+ super();
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+
+ this.state = {};
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+ var team = {};
+ var state = {serverError: ''};
+
+ team.email = this.refs.email.getDOMNode().value.trim().toLowerCase();
+ if (!team.email || !utils.isEmail(team.email)) {
+ state.emailError = 'Please enter a valid email address';
+ state.inValid = true;
+ } else {
+ state.emailError = '';
+ }
+
+ if (state.inValid) {
+ this.setState(state);
+ return;
+ }
+
+ client.signupTeam(team.email,
+ function success(data) {
+ if (data.follow_link) {
+ window.location.href = data.follow_link;
+ } else {
+ window.location.href = '/signup_team_confirm/?email=' + encodeURIComponent(team.email);
+ }
+ },
+ function fail(err) {
+ state.serverError = err.message;
+ this.setState(state);
+ }.bind(this)
+ );
+ }
+ render() {
+ return (
+ <form
+ role='form'
+ onSubmit={this.handleSubmit}
+ >
+ <div className='form-group'>
+ <input
+ autoFocus={true}
+ type='email'
+ ref='email'
+ className='form-control'
+ placeholder='Email Address'
+ maxLength='128'
+ />
+ </div>
+ <div className='form-group'>
+ <button
+ className='btn btn-md btn-primary'
+ type='submit'
+ >
+ Sign up
+ </button>
+ </div>
+ <div className='form-group margin--extra-2x'>
+ <span><a href='/find_team'>{'Find my ' + strings.Team}</a></span>
+ </div>
+ </form>
+ );
+ }
+}
+
+EmailSignUpPage.defaultProps = {
+};
+EmailSignUpPage.propTypes = {
+};
diff --git a/web/react/components/team_signup_with_sso.jsx b/web/react/components/team_signup_with_sso.jsx
new file mode 100644
index 000000000..57996d7cc
--- /dev/null
+++ b/web/react/components/team_signup_with_sso.jsx
@@ -0,0 +1,137 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var utils = require('../utils/utils.jsx');
+var client = require('../utils/client.jsx');
+var Constants = require('../utils/constants.jsx');
+
+export default class SSOSignUpPage extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.nameChange = this.nameChange.bind(this);
+
+ this.state = {name: ''};
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+ var team = {};
+ var state = this.state;
+ state.nameError = null;
+ state.serverError = null;
+
+ team.display_name = this.state.name;
+
+ if (team.display_name.length <= 3) {
+ return;
+ }
+
+ if (!team.display_name) {
+ state.nameError = 'Please enter a team name';
+ this.setState(state);
+ return;
+ }
+
+ team.name = utils.cleanUpUrlable(team.display_name);
+ team.type = 'O';
+
+ client.createTeamWithSSO(team,
+ this.props.service,
+ function success(data) {
+ if (data.follow_link) {
+ window.location.href = data.follow_link;
+ } else {
+ window.location.href = '/';
+ }
+ },
+ function fail(err) {
+ state.serverError = err.message;
+ this.setState(state);
+ }.bind(this)
+ );
+ }
+ nameChange() {
+ this.setState({name: this.refs.teamname.getDOMNode().value.trim()});
+ }
+ render() {
+ var nameError = null;
+ var nameDivClass = 'form-group';
+ if (this.state.nameError) {
+ nameError = <label className='control-label'>{this.state.nameError}</label>;
+ nameDivClass += ' has-error';
+ }
+
+ var serverError = null;
+ if (this.state.serverError) {
+ serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
+ }
+
+ var disabled = false;
+ if (this.state.name.length <= 3) {
+ disabled = true;
+ }
+
+ var button = null;
+
+ if (this.props.service === Constants.GITLAB_SERVICE) {
+ button = (
+ <a
+ className='btn btn-custom-login gitlab btn-full'
+ href='#'
+ onClick={this.handleSubmit}
+ disabled={disabled}
+ >
+ <span className='icon'/>
+ <span>Create {strings.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 {strings.Team} with Google Apps Account</span>
+ </a>
+ );
+ }
+
+ return (
+ <form
+ role='form'
+ onSubmit={this.handleSubmit}
+ >
+ <div className={nameDivClass}>
+ <input
+ autoFocus={true}
+ type='text'
+ ref='teamname'
+ className='form-control'
+ placeholder='Enter name of new team'
+ maxLength='128'
+ onChange={this.nameChange}
+ />
+ {nameError}
+ </div>
+ <div className='form-group'>
+ {button}
+ {serverError}
+ </div>
+ <div className='form-group margin--extra-2x'>
+ <span><a href='/find_team'>{'Find my ' + strings.Team}</a></span>
+ </div>
+ </form>
+ );
+ }
+}
+
+SSOSignUpPage.defaultProps = {
+ service: ''
+};
+SSOSignUpPage.propTypes = {
+ service: React.PropTypes.string
+};