Unverified Commit fcd2be45 authored by Martin Kraft's avatar Martin Kraft Committed by GitHub
Browse files

Merge branch 'master' into advanced-permissions-phase-2

parents c75e9a6c 790b5f20
......@@ -3,12 +3,12 @@
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {isChannelMuted} from 'mattermost-redux/utils/channel_utils';
import {isSystemMessage} from 'mattermost-redux/utils/post_utils';
import ChannelStore from 'stores/channel_store.jsx';
import NotificationStore from 'stores/notification_store.jsx';
import UserStore from 'stores/user_store.jsx';
import Constants, {NotificationLevels, UserStatuses} from 'utils/constants.jsx';
import {isSystemMessage} from 'utils/post_utils.jsx';
import {isMacApp, isMobileApp, isWindowsApp} from 'utils/user_agent.jsx';
import * as Utils from 'utils/utils.jsx';
import store from 'stores/redux_store.jsx';
......
......@@ -3,7 +3,7 @@
import $ from 'jquery';
import {batchActions} from 'redux-batched-actions';
import {ChannelTypes, EmojiTypes, PostTypes, TeamTypes, UserTypes, RoleTypes, GeneralTypes} from 'mattermost-redux/action_types';
import {ChannelTypes, EmojiTypes, PostTypes, TeamTypes, UserTypes, RoleTypes, GeneralTypes, AdminTypes} from 'mattermost-redux/action_types';
import {WebsocketEvents, General} from 'mattermost-redux/constants';
import {getChannelAndMyMember, getChannelStats, viewChannel} from 'mattermost-redux/actions/channels';
import {setServerVersion} from 'mattermost-redux/actions/general';
......@@ -287,6 +287,10 @@ function handleEvent(msg) {
handleLicenseChanged(msg);
break;
case SocketEvents.PLUGIN_STATUSES_CHANGED:
handlePluginStatusesChangedEvent(msg);
break;
default:
}
}
......@@ -702,3 +706,7 @@ function handleConfigChanged(msg) {
function handleLicenseChanged(msg) {
store.dispatch({type: GeneralTypes.CLIENT_LICENSE_RECEIVED, data: msg.data.license});
}
function handlePluginStatusesChangedEvent(msg) {
store.dispatch({type: AdminTypes.RECEIVED_PLUGIN_STATUSES, data: msg.data.plugin_statuses});
}
......@@ -31,6 +31,7 @@ export default class EmailSettings extends AdminSettings {
getConfigFromState(config) {
config.EmailSettings.SendEmailNotifications = this.state.sendEmailNotifications;
config.EmailSettings.EnablePreviewModeBanner = this.state.enablePreviewModeBanner;
config.EmailSettings.FeedbackName = this.state.feedbackName;
config.EmailSettings.FeedbackEmail = this.state.feedbackEmail;
config.EmailSettings.FeedbackOrganization = this.state.feedbackOrganization;
......@@ -49,7 +50,7 @@ export default class EmailSettings extends AdminSettings {
}
handleSaved(newConfig) {
if (newConfig.EmailSettings.SendEmailNotifications) {
if (newConfig.EmailSettings.SendEmailNotifications || !newConfig.EmailSettings.EnablePreviewModeBanner) {
ErrorStore.clearError(ErrorBarTypes.PREVIEW_MODE);
}
}
......@@ -57,6 +58,7 @@ export default class EmailSettings extends AdminSettings {
getStateFromConfig(config) {
return {
sendEmailNotifications: config.EmailSettings.SendEmailNotifications,
enablePreviewModeBanner: config.EmailSettings.EnablePreviewModeBanner,
feedbackName: config.EmailSettings.FeedbackName,
feedbackEmail: config.EmailSettings.FeedbackEmail,
feedbackOrganization: config.EmailSettings.FeedbackOrganization,
......@@ -168,13 +170,32 @@ export default class EmailSettings extends AdminSettings {
helpText={
<FormattedHTMLMessage
id='admin.email.notificationsDescription'
defaultMessage='Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.<br />Setting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).'
defaultMessage='Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.'
/>
}
value={this.state.sendEmailNotifications}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('EmailSettings.SendEmailNotifications')}
/>
<BooleanSetting
id='enablePreviewModeBanner'
label={
<FormattedMessage
id='admin.email.enablePreviewModeBannerTitle'
defaultMessage='Enable Preview Mode Banner:'
/>
}
helpText={
<FormattedHTMLMessage
id='admin.email.enablePreviewModeBannerDescription'
defaultMessage='When true, the Preview Mode banner is displayed so users are aware that email notifications are disabled. When false, the Preview Mode banner is not displayed to users.'
/>
}
value={this.state.enablePreviewModeBanner}
onChange={this.handleChange}
disabled={this.state.sendEmailNotifications}
setByEnv={this.isSetByEnv('EmailSettings.EnablePreviewModeBanner')}
/>
<BooleanSetting
id='enableEmailBatching'
label={
......
......@@ -35,42 +35,37 @@ export default class PasswordSettings extends AdminSettings {
});
// Update sample message from config settings
this.sampleErrorMsg = null;
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (props.config.PasswordSettings.Lowercase) {
sampleErrorMsgId += 'Lowercase';
}
if (props.config.PasswordSettings.Uppercase) {
sampleErrorMsgId += 'Uppercase';
}
if (props.config.PasswordSettings.Number) {
sampleErrorMsgId += 'Number';
}
if (props.config.PasswordSettings.Symbol) {
sampleErrorMsgId += 'Symbol';
}
this.sampleErrorMsg = (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
/>
);
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (props.config.PasswordSettings.Lowercase) {
sampleErrorMsgId += 'Lowercase';
}
if (props.config.PasswordSettings.Uppercase) {
sampleErrorMsgId += 'Uppercase';
}
if (props.config.PasswordSettings.Number) {
sampleErrorMsgId += 'Number';
}
if (props.config.PasswordSettings.Symbol) {
sampleErrorMsgId += 'Symbol';
}
this.sampleErrorMsg = (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
/>
);
}
getConfigFromState(config) {
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, Constants.MIN_PASSWORD_LENGTH);
config.PasswordSettings.Lowercase = this.refs.lowercase.checked;
config.PasswordSettings.Uppercase = this.refs.uppercase.checked;
config.PasswordSettings.Number = this.refs.number.checked;
config.PasswordSettings.Symbol = this.refs.symbol.checked;
}
config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, Constants.MIN_PASSWORD_LENGTH);
config.PasswordSettings.Lowercase = this.refs.lowercase.checked;
config.PasswordSettings.Uppercase = this.refs.uppercase.checked;
config.PasswordSettings.Number = this.refs.number.checked;
config.PasswordSettings.Symbol = this.refs.symbol.checked;
config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts);
......@@ -89,41 +84,37 @@ export default class PasswordSettings extends AdminSettings {
}
getSampleErrorMsg(minLength) {
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
return (
<FormattedMessage
id='user.settings.security.passwordMinLength'
default='Invalid minimum length, cannot show preview.'
/>
);
}
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (this.refs.lowercase.checked) {
sampleErrorMsgId += 'Lowercase';
}
if (this.refs.uppercase.checked) {
sampleErrorMsgId += 'Uppercase';
}
if (this.refs.number.checked) {
sampleErrorMsgId += 'Number';
}
if (this.refs.symbol.checked) {
sampleErrorMsgId += 'Symbol';
}
if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
return (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (minLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
id='user.settings.security.passwordMinLength'
default='Invalid minimum length, cannot show preview.'
/>
);
}
return null;
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (this.refs.lowercase.checked) {
sampleErrorMsgId += 'Lowercase';
}
if (this.refs.uppercase.checked) {
sampleErrorMsgId += 'Uppercase';
}
if (this.refs.number.checked) {
sampleErrorMsgId += 'Number';
}
if (this.refs.symbol.checked) {
sampleErrorMsgId += 'Symbol';
}
return (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (minLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
/>
);
}
handlePasswordLengthChange(id, value) {
......@@ -146,9 +137,8 @@ export default class PasswordSettings extends AdminSettings {
}
renderSettings() {
let passwordSettings = null;
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
passwordSettings = (
return (
<SettingsGroup>
<div>
<TextSetting
id='passwordMinimumLength'
......@@ -254,12 +244,6 @@ export default class PasswordSettings extends AdminSettings {
</div>
</Setting>
</div>
);
}
return (
<SettingsGroup>
{passwordSettings}
<TextSetting
id='maximumLoginAttempts'
label={
......
......@@ -3,7 +3,7 @@
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getPlugins, removePlugin, uploadPlugin, activatePlugin, deactivatePlugin} from 'mattermost-redux/actions/admin';
import {getPluginStatuses, removePlugin, uploadPlugin, activatePlugin, deactivatePlugin} from 'mattermost-redux/actions/admin';
import PluginManagement from './plugin_management.jsx';
......@@ -11,6 +11,7 @@ function mapStateToProps(state, ownProps) {
return {
...ownProps,
plugins: state.entities.admin.plugins,
pluginStatuses: state.entities.admin.pluginStatuses,
};
}
......@@ -19,7 +20,7 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators({
uploadPlugin,
removePlugin,
getPlugins,
getPluginStatuses,
activatePlugin,
deactivatePlugin,
}, dispatch),
......
......@@ -62,9 +62,9 @@ export default class ResetPasswordModal extends React.Component {
const password = this.refs.password.value;
const passwordErr = Utils.isValidPassword(password, this.props.passwordConfig);
if (passwordErr) {
this.setState({serverErrorNewPass: passwordErr});
const {valid, error} = Utils.isValidPassword(password, this.props.passwordConfig);
if (!valid && error) {
this.setState({serverErrorNewPass: error});
return;
}
......
......@@ -40,6 +40,7 @@ export default class AnnouncementBar extends React.PureComponent {
bannerText: PropTypes.string,
allowBannerDismissal: PropTypes.bool.isRequired,
enableBanner: PropTypes.bool.isRequired,
enablePreviewMode: PropTypes.bool.isRequired,
bannerColor: PropTypes.string,
bannerTextColor: PropTypes.string,
enableSignUpWithGitLab: PropTypes.bool.isRequired,
......@@ -76,7 +77,7 @@ export default class AnnouncementBar extends React.PureComponent {
if (this.props.canViewSystemErrors && this.props.siteURL === '') {
ErrorStore.storeLastError({notification: true, message: ErrorBarTypes.SITE_URL});
return;
} else if (!this.props.sendEmailNotifications) {
} else if (!this.props.sendEmailNotifications && this.props.enablePreviewMode) {
ErrorStore.storeLastError({notification: true, message: ErrorBarTypes.PREVIEW_MODE});
return;
}
......
......@@ -18,6 +18,7 @@ function mapStateToProps(state) {
const licenseId = license.Id;
const siteURL = config.SiteURL;
const sendEmailNotifications = config.SendEmailNotifications === 'true';
const enablePreviewMode = config.EnablePreviewModeBanner === 'true';
const bannerText = config.BannerText;
const allowBannerDismissal = config.AllowBannerDismissal === 'true';
const enableBanner = config.EnableBanner === 'true';
......@@ -35,6 +36,7 @@ function mapStateToProps(state) {
bannerText,
allowBannerDismissal,
enableBanner,
enablePreviewMode,
bannerColor,
bannerTextColor,
enableSignUpWithGitLab,
......
......@@ -19,10 +19,10 @@ import ChannelStore from 'stores/channel_store.jsx';
import MessageWrapper from 'components/message_wrapper.jsx';
import {Constants, NotificationLevels, RHSStates, UserStatuses, ModalIdentifiers} from 'utils/constants.jsx';
import messageHtmlToComponent from 'utils/message_html_to_component';
import * as TextFormatting from 'utils/text_formatting.jsx';
import {getSiteURL} from 'utils/url.jsx';
import * as Utils from 'utils/utils.jsx';
import {messageHtmlToComponent} from 'utils/post_utils.jsx';
import ChannelInfoModal from 'components/channel_info_modal';
import ChannelInviteModal from 'components/channel_invite_modal';
import ChannelMembersModal from 'components/channel_members_modal';
......
......@@ -48,10 +48,10 @@ export default class LDAPToEmail extends React.Component {
return;
}
const passwordErr = Utils.isValidPassword(password, this.props.passwordConfig);
if (passwordErr !== '') {
const {valid, error} = Utils.isValidPassword(password, this.props.passwordConfig);
if (!valid && error) {
this.setState({
passwordError: passwordErr,
passwordError: error,
});
return;
}
......
......@@ -30,11 +30,9 @@ export default class OAuthToEmail extends React.Component {
return;
}
const passwordErr = Utils.isValidPassword(password, this.props.passwordConfig);
if (passwordErr !== '') {
this.setState({
error: passwordErr,
});
const {valid, error} = Utils.isValidPassword(password, this.props.passwordConfig);
if (!valid && error) {
this.setState({error});
return;
}
......
......@@ -17,9 +17,9 @@ import TeamStore from 'stores/team_store.jsx';
import {browserHistory} from 'utils/browser_history';
import Constants from 'utils/constants.jsx';
import messageHtmlToComponent from 'utils/message_html_to_component';
import * as TextFormatting from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx';
import {messageHtmlToComponent} from 'utils/post_utils.jsx';
import logoImage from 'images/logo.png';
......
......@@ -4,10 +4,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import messageHtmlToComponent from 'utils/message_html_to_component';
import * as TextFormatting from 'utils/text_formatting.jsx';
import {getSiteURL} from 'utils/url.jsx';
import * as Utils from 'utils/utils.jsx';
import {messageHtmlToComponent} from 'utils/post_utils.jsx';
export default class MessageWrapper extends React.Component {
constructor(props) {
......
......@@ -4,7 +4,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import * as PostUtils from 'utils/post_utils.jsx';
import messageHtmlToComponent from 'utils/message_html_to_component';
import * as TextFormatting from 'utils/text_formatting.jsx';
import {renderSystemMessage} from './system_message_helpers.jsx';
......@@ -83,6 +83,6 @@ export default class PostMarkdown extends React.PureComponent {
}
const htmlFormattedText = TextFormatting.formatText(this.props.message, options);
return PostUtils.messageHtmlToComponent(htmlFormattedText, this.props.isRHS);
return messageHtmlToComponent(htmlFormattedText, this.props.isRHS);
}
}
......@@ -5,8 +5,8 @@ import PropTypes from 'prop-types';
import React from 'react';
import * as PostActions from 'actions/post_actions.jsx';
import messageHtmlToComponent from 'utils/message_html_to_component';
import * as TextFormatting from 'utils/text_formatting.jsx';
import {messageHtmlToComponent} from 'utils/post_utils.jsx';
import {isUrlSafe} from 'utils/url.jsx';
import {localizeMessage} from 'utils/utils.jsx';
......
......@@ -32,7 +32,10 @@ export default class SettingItemMax extends React.PureComponent {
/**
* Client error
*/
clientError: PropTypes.string,
clientError: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
]),
/**
* Server error
......
......@@ -218,12 +218,12 @@ export default class SignupEmail extends React.Component {
}
const providedPassword = this.refs.password.value;
const pwdError = Utils.isValidPassword(providedPassword, this.props.passwordConfig);
if (pwdError) {
const {valid, error} = Utils.isValidPassword(providedPassword, this.props.passwordConfig);
if (!valid && error) {
this.setState({
nameError: '',
emailError: '',
passwordError: pwdError,
passwordError: error,
serverError: '',
});
return false;
......
......@@ -126,10 +126,10 @@ export default class SecurityTab extends React.Component {
return;
}
const passwordErr = Utils.isValidPassword(newPassword, this.props.passwordConfig);
if (passwordErr !== '') {
const {valid, error} = Utils.isValidPassword(newPassword, this.props.passwordConfig);
if (!valid && error) {
this.setState({
passwordError: passwordErr,
passwordError: error,
serverError: '',
});
return;
......
......@@ -503,6 +503,8 @@
"admin.email.enableEmailBatching.siteURL": "Email batching cannot be enabled unless the SiteURL is configured in <b>Configuration > SiteURL</b>.",
"admin.email.enableEmailBatchingDesc": "When true, users will have email notifications for multiple direct messages and mentions combined into a single email. Batching will occur at a default interval of 15 minutes, configurable in Account Settings > Notifications.",
"admin.email.enableEmailBatchingTitle": "Enable Email Batching:",
"admin.email.enablePreviewModeBannerTitle": "Enable Preview Mode Banner:",
"admin.email.enablePreviewModeBannerDescription": "When true, the Preview Mode banner is displayed so users are aware that email notifications are disabled. When false, the Preview Mode banner is not displayed to users.",
"admin.email.enableSMTPAuthDesc": "When enabled, username and password are used for authenticating to the SMTP server.",
"admin.email.enableSMTPAuthTitle": "Enable SMTP Authentication:",
"admin.email.fullPushNotification": "Send full message snippet",
......@@ -530,7 +532,7 @@
"admin.email.notificationOrganization": "Notification Footer Mailing Address:",
"admin.email.notificationOrganizationDescription": "Organization name and address displayed on email notifications from Mattermost, such as \"© ABC Corporation, 565 Knight Way, Palo Alto, California, 94305, USA\". If the field is left empty, the organization name and address will not be displayed.",
"admin.email.notificationOrganizationExample": "E.g.: \"© ABC Corporation, 565 Knight Way, Palo Alto, California, 94305, USA\"",
"admin.email.notificationsDescription": "Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.<br />Setting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).",
"admin.email.notificationsDescription": "Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.",
"admin.email.notificationsTitle": "Enable Email Notifications: ",
"admin.email.passwordSaltDescription": "32-character salt added to signing of password reset emails. Randomly generated on install. Click \"Regenerate\" to create new salt.",
"admin.email.passwordSaltExample": "E.g.: \"bjlSR4QqkXFBr7TP4oDzlfZmcNuH9Yo\"",
......@@ -874,6 +876,7 @@
"admin.plugin.activating": "Activating...",
"admin.plugin.banner": "Plugins are experimental and not recommended for use in production.",
"admin.plugin.choose": "Choose File",
"admin.plugin.cluster_instance": "Cluster Instance",
"admin.plugin.deactivate": "Deactivate",
"admin.plugin.deactivating": "Deactivating...",
"admin.plugin.desc": "Description:",
......@@ -884,18 +887,34 @@
"admin.plugin.installedTitle": "Installed Plugins: ",
"admin.plugin.management.banner": "Plugins are disabled on your server. To enable them, go to <strong>Plugins > Configuration</strong>.",
"admin.plugin.management.title": "Management",
"admin.plugin.multiple_versions_warning": "There are multiple versions of this plugin installed across your cluster. Re-install this plugin to ensure it works consistently.",
"admin.plugin.name": "Name:",
"admin.plugin.no_plugins": "No installed plugins.",
"admin.plugin.prepackaged": "Pre-packaged",
"admin.plugin.prepackaged": "pre-packaged",
"admin.plugin.remove": "Remove",
"admin.plugin.removing": "Removing...",
"admin.plugin.settingsButton": "Settings",
"admin.plugin.state": "State",
"admin.plugin.state.failed_to_start": "Failed to start",
"admin.plugin.state.failed_to_start.description": "This plugin failed to start. Check your system logs for errors.",
"admin.plugin.state.failed_to_stay_running": "Crashing",
"admin.plugin.state.failed_to_stay_running.description": "This plugin crashed multiple times and is no longer running. Check your system logs for errors.",
"admin.plugin.state.not_running": "Not running",
"admin.plugin.state.not_running.description": "This plugin is not activated.",
"admin.plugin.state.running": "Running",
"admin.plugin.state.running.description": "This plugin is running.",
"admin.plugin.state.starting": "Starting",
"admin.plugin.state.starting.description": "This plugin is starting.",
"admin.plugin.state.stopping": "Stopping",
"admin.plugin.state.stopping.description": "This plugin is stopping.",
"admin.plugin.state.unknown": "Unknown",
"admin.plugin.upload": "Upload",
"admin.plugin.uploadDesc": "Upload a plugin for your Mattermost server. See <a href=\"https://about.mattermost.com/default-plugin-uploads\" target=\"_blank\">documentation</a> to learn more.",
"admin.plugin.uploadDisabledDesc": "To enable plugin uploads, go to <strong>Plugins > Configuration</strong>. See <a href=\"https://about.mattermost.com/default-plugin-uploads\" target=\"_blank\">documentation</a> to learn more.",
"admin.plugin.uploadTitle": "Upload Plugin: ",
"admin.plugin.uploading": "Uploading...",
"admin.plugin.version": "Version:",
"admin.plugin.version_title": "Version",
"admin.plugins.settings.enable": "Enable Plugins: ",
"admin.plugins.settings.enableDesc": "When true, enables plugins on your Mattermost server. Use plugins to integrate with third-party systems, extend functionality or customize the user interface of your Mattermost server. See <a href=\"https://about.mattermost.com/default-plugins\" target=\"_blank\">documentation</a> to learn more.",
"admin.plugins.settings.title": "Configuration",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment