From 5985a0c531c5b554d4a45048aa461073d5ea3cf6 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 23 Jan 2024 08:52:22 -0700 Subject: [PATCH] [MM-51521] Prevent adjusting password stength fields when set in environment (#24151) Co-authored-by: Nathan Geist --- .../checkbox_setting.test.tsx.snap | 33 +++++++ .../admin_console/checkbox_setting.test.tsx | 50 +++++++++++ .../admin_console/checkbox_setting.tsx | 67 ++++++++++++++ .../admin_console/password_settings.tsx | 87 ++++++++++--------- .../src/components/admin_console/setting.tsx | 23 +++-- 5 files changed, 210 insertions(+), 50 deletions(-) create mode 100644 webapp/channels/src/components/admin_console/__snapshots__/checkbox_setting.test.tsx.snap create mode 100644 webapp/channels/src/components/admin_console/checkbox_setting.test.tsx create mode 100644 webapp/channels/src/components/admin_console/checkbox_setting.tsx diff --git a/webapp/channels/src/components/admin_console/__snapshots__/checkbox_setting.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/checkbox_setting.test.tsx.snap new file mode 100644 index 0000000000..f86662a37b --- /dev/null +++ b/webapp/channels/src/components/admin_console/__snapshots__/checkbox_setting.test.tsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/admin_console/CheckboxSetting should match snapshot 1`] = ` +
+ +`; diff --git a/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx b/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx new file mode 100644 index 0000000000..4ebd8aea28 --- /dev/null +++ b/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx @@ -0,0 +1,50 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils'; + +import CheckboxSetting from './checkbox_setting'; + +describe('components/admin_console/CheckboxSetting', () => { + test('should match snapshot', () => { + const onChange = jest.fn(); + const {container} = renderWithContext( + , + ); + const checkbox: HTMLInputElement = screen.getByRole('checkbox'); + expect(checkbox).toBeVisible(); + expect(checkbox).toHaveProperty('type', 'checkbox'); + expect(container).toMatchSnapshot(); + }); + + test('onChange', () => { + const onChange = jest.fn(); + renderWithContext( + , + ); + const checkbox: HTMLInputElement = screen.getByRole('checkbox'); + expect(checkbox).not.toBeChecked(); + + fireEvent.click(checkbox); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith('string.id', true); + expect(checkbox).toBeChecked(); + }); +}); diff --git a/webapp/channels/src/components/admin_console/checkbox_setting.tsx b/webapp/channels/src/components/admin_console/checkbox_setting.tsx new file mode 100644 index 0000000000..b74d5c917a --- /dev/null +++ b/webapp/channels/src/components/admin_console/checkbox_setting.tsx @@ -0,0 +1,67 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import Setting from './setting'; + +type Props = { + id: string; + label: React.ReactNode; + defaultChecked?: boolean; + onChange: (id: string, foo: boolean) => void; + disabled: boolean; + setByEnv: boolean; + disabledText?: React.ReactNode; + helpText?: React.ReactNode; +} + +export default class CheckboxSetting extends React.PureComponent { + public static defaultProps = { + disabled: false, + }; + + private handleChange = (e: React.ChangeEvent) => { + this.props.onChange(this.props.id, e.target.checked); + }; + + public render() { + let helpText; + if (this.props.disabled && this.props.disabledText) { + helpText = ( +
+ + {this.props.disabledText} + + {this.props.helpText} +
+ ); + } else { + helpText = this.props.helpText; + } + + return ( + +
+ + + ); + } +} diff --git a/webapp/channels/src/components/admin_console/password_settings.tsx b/webapp/channels/src/components/admin_console/password_settings.tsx index 0ad0417fa1..4c30afa13e 100644 --- a/webapp/channels/src/components/admin_console/password_settings.tsx +++ b/webapp/channels/src/components/admin_console/password_settings.tsx @@ -14,6 +14,7 @@ import AdminSettings from './admin_settings'; import type {BaseProps, BaseState} from './admin_settings'; import BlockableLink from './blockable_link'; import BooleanSetting from './boolean_setting'; +import CheckboxSetting from './checkbox_setting'; import Setting from './setting'; import SettingsGroup from './settings_group'; import TextSetting from './text_setting'; @@ -182,9 +183,9 @@ export default class PasswordSettings extends AdminSettings { ); }; - handleCheckboxChange = (id: string) => { - return (event: React.ChangeEvent) => { - this.handleChange(id, event.target.checked); + handleBooleanChange = (id: string) => { + return (_: string, value: boolean) => { + this.handleChange(id, value); }; }; @@ -220,52 +221,52 @@ export default class PasswordSettings extends AdminSettings { label={} >
- + + } + defaultChecked={this.state.passwordLowercase} + onChange={this.handleBooleanChange('passwordLowercase')} + setByEnv={this.isSetByEnv('PasswordSettings.Lowercase')} + disabled={this.props.isDisabled} + />
- + + } + defaultChecked={this.state.passwordUppercase} + onChange={this.handleBooleanChange('passwordUppercase')} + setByEnv={this.isSetByEnv('PasswordSettings.Uppercase')} + disabled={this.props.isDisabled} + />
- + + } + defaultChecked={this.state.passwordNumber} + onChange={this.handleBooleanChange('passwordNumber')} + setByEnv={this.isSetByEnv('PasswordSettings.Number')} + disabled={this.props.isDisabled} + />
- + + } + defaultChecked={this.state.passwordSymbol} + onChange={this.handleBooleanChange('passwordSymbol')} + setByEnv={this.isSetByEnv('PasswordSettings.Symbol')} + disabled={this.props.isDisabled} + />

diff --git a/webapp/channels/src/components/admin_console/setting.tsx b/webapp/channels/src/components/admin_console/setting.tsx index f55bad38bb..0cc032518a 100644 --- a/webapp/channels/src/components/admin_console/setting.tsx +++ b/webapp/channels/src/components/admin_console/setting.tsx @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import classNames from 'classnames'; import React from 'react'; import SetByEnv from './set_by_env'; @@ -11,21 +12,29 @@ export type Props = { children?: React.ReactNode; helpText?: React.ReactNode; setByEnv?: boolean; + nested?: boolean; } -const Settings = ({children, setByEnv, helpText, inputId, label}: Props) => { +const Settings = ({children, setByEnv, helpText, inputId, label, nested = false}: Props) => { return (
- + )} +
- {label} - -
{children}