Skip to content

Commit

Permalink
MM-12130: Create a new page for displaying terms of service (mattermo…
Browse files Browse the repository at this point in the history
…st#1735)

* MM-12130: Create a new page for displaying terms of service

- Replace the Back Button with a Logout Button

- Add default props

Update shouldComponentUpdate

- Make Mattermost navigate to this page if user is already logged in has not accepted TOS and TOS is enabled

- Make Mattermost navigate to this page after logging in if user has not accepted TOS and TOS is enabled

- Add Loading screen and test cases.

- Handle Redirect while opening routes, App Navigation and login flow

- Added new config fields for service terms

- made service terms text field disabled if custom terms are disabled

- Integrate API request for Agree and Disagree Actions

- Use the currently logged in user instead of sending userId.

- Updated service terms messages to indicate that it is a beta feature

- Add tests

* Add action for new API call for getServiceTerms
Update tests accordingly

* Add test and fix check-style

* Update terms of service link

* Minor Fixes

* - Sent boolean for registerUserAction instead of string
- Update tests

* Remove Redirect Action

* hid custom service terms setting if feature is not enabled

* Update admin_definition.jsx

* Fix check-style

* check CustomTermsOfService in license

*     Minor Fixes
    - Do not update terms seen by user when config is updated
    - Update terms Help text
    - Do not stop loaders just before redirecting to another page
    - Footer buttons and text on terms_of_service page are aligned to bottom
    - Update tests accordingly

* Remove terms of service redirect from login controller
  • Loading branch information
chetanyakan authored and lieut-data committed Sep 28, 2018
1 parent 9fda083 commit af50cec
Show file tree
Hide file tree
Showing 17 changed files with 515 additions and 3 deletions.
18 changes: 18 additions & 0 deletions actions/user_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,24 @@ export async function webLogin(loginId, password, token, success, error) {
}
}

export async function updateServiceTermsStatus(serviceTermsId, accepted, success, error) {
const {data, error: err} = await UserActions.updateServiceTermsStatus(serviceTermsId, accepted)(dispatch, getState);
if (data && success) {
success(data);
} else if (err && error) {
error({id: err.server_error_id, ...err});
}
}

export async function getServiceTerms(success, error) {
const {data, error: err} = await UserActions.getServiceTerms()(dispatch, getState);
if (data && success) {
success(data);
} else if (err && error) {
error({id: err.server_error_id, ...err});
}
}

export async function webLoginByLdap(loginId, password, token, success, error) {
const {data: ok, error: err} = await UserActions.login(loginId, password, token, true)(dispatch, getState);
if (ok && success) {
Expand Down
20 changes: 20 additions & 0 deletions components/admin_console/admin_definition.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2773,6 +2773,26 @@ export default {
help_text: t('admin.support.emailHelp'),
help_text_default: 'Email address displayed on email notifications and during tutorial for end users to ask support questions.',
},
{
type: Constants.SettingsTypes.TYPE_BOOL,
key: 'SupportSettings.CustomServiceTermsEnabled',
label: 'admin.support.enableServiceTermsTitle',
label_default: 'Enable Custom Terms of Service (Beta)',
help_text: 'admin.support.serviceTermsHelp',
help_text_default: 'When true, new users must accept the terms of service before accessing any Mattermost teams on desktop, web or mobile. Existing users must accept them after login or a page refresh.\n \nUsers on mobile do not have to accept the terms of service with mobile support scheduled for an upcoming release.',
help_text_markdown: true,
isHidden: needsUtils.not(needsUtils.hasLicenseFeature('CustomTermsOfService')),
},
{
type: Constants.SettingsTypes.TYPE_LONG_TEXT,
key: 'SupportSettings.CustomServiceTermsText',
label: 'admin.support.serviceTermsTextTitle',
label_default: 'Custom Terms of Service Text (Beta)',
isDisabled: needsUtils.stateValueFalse('SupportSettings.CustomServiceTermsEnabled'),
isHidden: needsUtils.not(needsUtils.hasLicenseFeature('CustomTermsOfService')),
help_text: 'admin.support.serviceTermsTextHelp',
help_text_default: 'Text that will appear in your custom Terms of Service. Supports Markdown-formatted text.',
},
],
},
},
Expand Down
4 changes: 4 additions & 0 deletions components/logged_in/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ import {bindActionCreators} from 'redux';
import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone';
import {getLicense, getConfig} from 'mattermost-redux/selectors/entities/general';

import {showCustomTerms} from 'mattermost-redux/selectors/entities/users';

import {checkIfMFARequired} from 'utils/route';

import LoggedIn from './logged_in.jsx';

function mapStateToProps(state, ownProps) {
const license = getLicense(state);
const config = getConfig(state);
const showTermsOfService = showCustomTerms(state);

return {
mfaRequired: checkIfMFARequired(license, config, ownProps.match.url),
enableTimezone: config.ExperimentalTimezone === 'true',
showTermsOfService,
};
}

Expand Down
6 changes: 6 additions & 0 deletions components/logged_in/logged_in.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import ChannelStore from 'stores/channel_store.jsx';
import ErrorStore from 'stores/error_store.jsx';
import * as UserAgent from 'utils/user_agent.jsx';
import * as Utils from 'utils/utils.jsx';
import {browserHistory} from 'utils/browser_history';
import LoadingScreen from 'components/loading_screen.jsx';
import {getBrowserTimezone} from 'utils/timezone.jsx';
import store from 'stores/redux_store.jsx';
Expand Down Expand Up @@ -97,6 +98,10 @@ export default class LoggedIn extends React.Component {
GlobalActions.emitUserLoggedOutEvent('/login?redirect_to=' + encodeURIComponent(this.props.location.pathname));
}

if (this.props.showTermsOfService && this.props.location.pathname !== '/terms_of_service') {
browserHistory.push('/terms_of_service?redirect_to=' + encodeURIComponent(this.props.location.pathname));
}

$('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) {
if (ev.type === 'mouseenter') {
$(this).prev('.date-separator, .new-separator').addClass('hovered--after');
Expand Down Expand Up @@ -180,4 +185,5 @@ LoggedIn.propTypes = {
actions: PropTypes.shape({
autoUpdateTimezone: PropTypes.func.isRequired,
}).isRequired,
showTermsOfService: PropTypes.bool.isRequired,
};
28 changes: 28 additions & 0 deletions components/login/login_controller/login_controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import logoImage from 'images/logo.png';
import SiteNameAndDescription from 'components/common/site_name_and_description';
import AnnouncementBar from 'components/announcement_bar';
import FormError from 'components/form_error.jsx';
import FormattedMarkdownMessage from 'components/formatted_markdown_message.jsx';
import BackButton from 'components/common/back_button.jsx';

import LoginMfa from '../login_mfa.jsx';
Expand Down Expand Up @@ -459,6 +460,33 @@ class LoginController extends React.Component {
</Link>
</div>
);
} else if (extraParam === Constants.GET_TERMS_ERROR) {
extraBox = (
<div className='alert has-error no-padding'>
<label className='control-label'>
<FormattedMessage
id='login.get_terms_error'
defaultMessage='Unable to load terms of service. If this issue persists, contact your System Administrator.'
/>
</label>
</div>
);
} else if (extraParam === Constants.TERMS_REJECTED) {
extraBox = (
<div className='alert alert-warning'>
<i
className='fa fa-exclamation-triangle'
title={Utils.localizeMessage('generic_icons.warning', 'Warning Icon')}
/>
<FormattedMarkdownMessage
id='login.terms_rejected'
defaultMessage='You must agree to the terms of service before accessing {siteName}. Please contact your System Administrator for more details.'
values={{
siteName: this.props.siteName,
}}
/>
</div>
);
} else if (extraParam === Constants.SIGNIN_CHANGE) {
extraBox = (
<div className='alert alert-success'>
Expand Down
4 changes: 4 additions & 0 deletions components/root/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
import {connect} from 'react-redux';
import {getConfig} from 'mattermost-redux/selectors/entities/general';

import {showCustomTerms} from 'mattermost-redux/selectors/entities/users';

import Root from './root.jsx';

function mapStateToProps(state) {
const config = getConfig(state);
const showTermsOfService = showCustomTerms(state);

return {
diagnosticsEnabled: config.DiagnosticsEnabled === 'true',
noAccounts: config.NoAccounts === 'true',
diagnosticId: config.DiagnosticId,
showTermsOfService,
};
}

Expand Down
9 changes: 9 additions & 0 deletions components/root/root.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import loadPasswordResetSendLink from 'bundle-loader?lazy!components/password_re
import loadPasswordResetForm from 'bundle-loader?lazy!components/password_reset_form';
import loadSignupController from 'bundle-loader?lazy!components/signup/signup_controller';
import loadSignupEmail from 'bundle-loader?lazy!components/signup/signup_email';
import loadTermsOfService from 'bundle-loader?lazy!components/terms_of_service';
import loadShouldVerifyEmail from 'bundle-loader?lazy!components/should_verify_email';
import loadDoVerifyEmail from 'bundle-loader?lazy!components/do_verify_email';
import loadClaimController from 'bundle-loader?lazy!components/claim';
Expand All @@ -55,6 +56,7 @@ import {getSiteURL} from 'utils/url.jsx';

const CreateTeam = makeAsyncComponent(loadCreateTeam);
const ErrorPage = makeAsyncComponent(loadErrorPage);
const TermsOfService = makeAsyncComponent(loadTermsOfService);
const LoginController = makeAsyncComponent(loadLoginController);
const AdminConsole = makeAsyncComponent(loadAdminConsole);
const LoggedIn = makeAsyncComponent(loadLoggedIn);
Expand Down Expand Up @@ -89,6 +91,7 @@ export default class Root extends React.Component {
diagnosticId: PropTypes.string,
noAccounts: PropTypes.bool,
children: PropTypes.object,
showTermsOfService: PropTypes.bool,
}

constructor(props) {
Expand Down Expand Up @@ -235,6 +238,8 @@ export default class Root extends React.Component {
if (props.location.pathname === '/') {
if (this.props.noAccounts) {
this.props.history.push('/signup_user_complete');
} else if (props.showTermsOfService) {
this.props.history.push('/terms_of_service');
} else if (UserStore.getCurrentUser()) {
GlobalActions.redirectUserToDefaultTeam();
}
Expand Down Expand Up @@ -307,6 +312,10 @@ export default class Root extends React.Component {
path={'/help'}
component={HelpController}
/>
<LoggedInHFTRoute
path={'/terms_of_service'}
component={TermsOfService}
/>
<Route
path={'/get_ios_app'}
component={GetIosApp}
Expand Down
5 changes: 4 additions & 1 deletion components/select_team/select_team.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ export default class SelectTeam extends React.Component {
className='fa fa-chevron-left'
title={Utils.localizeMessage('generic_icons.logout', 'Logout Icon')}
/>
<FormattedMessage id='web.header.logout'/>
<FormattedMessage
id='web.header.logout'
defaultMessage='Logout'
/>
</a>
</div>
);
Expand Down
21 changes: 21 additions & 0 deletions components/terms_of_service/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {connect} from 'react-redux';

import {getConfig} from 'mattermost-redux/selectors/entities/general';

import TermsOfService from './terms_of_service';

function mapStateToProps(state) {
const config = getConfig(state);
return {
customServiceTermsId: config.CustomServiceTermsId,
privacyPolicyLink: config.PrivacyPolicyLink,
siteName: config.SiteName,
termsEnabled: config.EnableCustomServiceTerms === 'true',
termsOfServiceLink: config.TermsOfServiceLink,
};
}

export default connect(mapStateToProps)(TermsOfService);
Loading

0 comments on commit af50cec

Please sign in to comment.