Add config setting to set default User Setting for filter join/leave message (#24047)

* initial submit, join/leave message

* i18n-extract

* additional changes for client config

* add unit tests

* fix unit tests

* change tests to use string not bool

* more unit test fixes

* add and fix unit tests

* revert package-lock

* update unit tests

* Update default_config.ts

* fix unit test

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Scott Bishel
2023-08-29 12:30:16 -06:00
коммит произвёл GitHub
родитель fe4a77498a
Коммит f35291169c
14 изменённых файлов: 293 добавлений и 19 удалений

Просмотреть файл

@@ -2277,6 +2277,15 @@ const AdminDefinition = {
placeholder_default: 'E.g.: "100"',
isDisabled: it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.SITE.USERS_AND_TEAMS)),
},
{
type: Constants.SettingsTypes.TYPE_BOOL,
key: 'TeamSettings.EnableJoinLeaveMessageByDefault',
label: t('admin.team.enableJoinLeaveMessageTitle'),
label_default: 'Enable join/leave messages by default:',
help_text: t('admin.team.enableJoinLeaveMessageDescription'),
help_text_default: 'Choose the default configuration of system messages displayed when users join or leave channels. Users can override this default by configuring Join/Leave messages in Account Settings > Advanced.',
isDisabled: it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.SITE.USERS_AND_TEAMS)),
},
{
type: Constants.SettingsTypes.TYPE_DROPDOWN,
key: 'TeamSettings.RestrictDirectMessage',

Просмотреть файл

@@ -25,13 +25,14 @@ function makeMapStateToProps() {
const enablePreviewFeatures = config.EnablePreviewFeatures === 'true';
const enableUserDeactivation = config.EnableUserDeactivation === 'true';
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
return {
advancedSettingsCategory: getAdvancedSettingsCategory(state, Preferences.CATEGORY_ADVANCED_SETTINGS),
sendOnCtrlEnter: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter', 'false'),
codeBlockOnCtrlEnter: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'code_block_ctrl_enter', 'true'),
formatting: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', 'true'),
joinLeave: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'join_leave', 'true'),
joinLeave: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'join_leave', enableJoinLeaveMessage.toString()),
syncDrafts: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'sync_drafts', 'true'),
currentUser: getCurrentUser(state),
unreadScrollPosition: getUnreadScrollPositionPreference(state),

Просмотреть файл

@@ -4,8 +4,9 @@
import {bindActionCreators, Dispatch} from 'redux';
import {connect} from 'react-redux';
import {GlobalState} from 'types/store/index.js';
import {GlobalState} from 'types/store';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {GenericAction} from 'mattermost-redux/types/actions.js';
import {savePreferences} from 'mattermost-redux/actions/preferences';
@@ -15,12 +16,15 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import JoinLeaveSection from './join_leave_section';
function mapStateToProps(state: GlobalState) {
export function mapStateToProps(state: GlobalState) {
const config = getConfig(state);
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
const joinLeave = getPreference(
state,
Preferences.CATEGORY_ADVANCED_SETTINGS,
Preferences.ADVANCED_FILTER_JOIN_LEAVE,
'true',
enableJoinLeaveMessage.toString(),
);
return {

Просмотреть файл

@@ -3,6 +3,11 @@
import React from 'react';
import {shallow} from 'enzyme';
import {GlobalState} from 'types/store';
import mergeObjects from 'packages/mattermost-redux/test/merge_objects';
import {Preferences} from 'mattermost-redux/constants';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
import {AdvancedSections} from 'utils/constants';
@@ -114,3 +119,92 @@ describe('components/user_settings/advanced/JoinLeaveSection', () => {
expect(onUpdateSection).toBeCalledWith(AdvancedSections.JOIN_LEAVE);
});
});
import {mapStateToProps} from './index';
describe('mapStateToProps', () => {
const currentUserId = 'user-id';
const initialState = {
currentUserId,
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
preferences: {
myPreferences: {},
},
users: {
currentUserId,
profiles: {
[currentUserId]: {
id: currentUserId,
},
},
},
},
} as unknown as GlobalState;
test('configuration default to true', () => {
const props = mapStateToProps(initialState);
expect(props.joinLeave).toEqual('true');
});
test('configuration default to false', () => {
const testState = mergeObjects(initialState, {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'false',
},
},
},
});
const props = mapStateToProps(testState);
expect(props.joinLeave).toEqual('false');
});
test('user setting takes presidence', () => {
const testState = mergeObjects(initialState, {
entities: {
general: {
config: {
EnableJoinDefault: 'false',
},
},
preferences: {
myPreferences: {
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
value: 'true',
},
},
},
},
});
const props = mapStateToProps(testState);
expect(props.joinLeave).toEqual('true');
});
test('user setting takes presidence opposite', () => {
const testState = mergeObjects(initialState, {
entities: {
preferences: {
myPreferences: {
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
value: 'false',
},
},
},
},
});
const props = mapStateToProps(testState);
expect(props.joinLeave).toEqual('false');
});
});

Просмотреть файл

@@ -2484,6 +2484,8 @@
"admin.team.customUserStatusesTitle": "Enable Custom Statuses: ",
"admin.team.emailInvitationsDescription": "When true users can invite others to the system using email.",
"admin.team.emailInvitationsTitle": "Enable Email Invitations: ",
"admin.team.enableJoinLeaveMessageDescription": "Choose the default configuration of system messages displayed when users join or leave channels. Users can override this default by configuring Join/Leave messages in Account Settings > Advanced.",
"admin.team.enableJoinLeaveMessageTitle": "Enable join/leave messages by default:",
"admin.team.invalidateEmailInvitesDescription": "This will invalidate active email invitations that have not been accepted by the user. By default email invitations expire after 48 hours.",
"admin.team.invalidateEmailInvitesFail": "Unable to invalidate pending email invites: {error}",
"admin.team.invalidateEmailInvitesSuccess": "Pending email invitations invalidated successfully",

Просмотреть файл

@@ -33,12 +33,12 @@ describe('Actions.Posts', () => {
general: {
config: {
CollapsedThreads: 'always_on',
EnableJoinLeaveMessageByDefault: 'true',
},
},
},
});
});
afterAll(() => {
TestHelper.tearDown();
});

Просмотреть файл

@@ -43,6 +43,11 @@ describe('Selectors.Posts', () => {
const testState = deepFreezeAndThrowOnMutation({
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
users: {
currentUserId: user1.id,
profiles,
@@ -802,6 +807,9 @@ describe('Selectors.Posts', () => {
const state = {
entities: {
general: {
config: {},
},
users: {
currentUserId: user1.id,
profiles,
@@ -833,6 +841,9 @@ describe('Selectors.Posts', () => {
const state = {
entities: {
general: {
config: {},
},
users: {
currentUserId: user1.id,
profiles,
@@ -864,6 +875,9 @@ describe('Selectors.Posts', () => {
let state = {
entities: {
general: {
config: {},
},
users: {
currentUserId: user1.id,
profiles,
@@ -983,6 +997,9 @@ describe('Selectors.Posts', () => {
const state = {
entities: {
general: {
config: {},
},
users: {
currentUserId: user1.id,
profiles,
@@ -2472,6 +2489,11 @@ describe('makeGetProfilesForThread', () => {
const state = {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
posts: {
posts: {
1001: {id: '1001', create_at: 1001, user_id: 'user1'},
@@ -2507,6 +2529,11 @@ describe('makeGetProfilesForThread', () => {
const state = {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
posts: {
posts: {
1001: {id: '1001', create_at: 1001, user_id: 'user1'},

Просмотреть файл

@@ -24,6 +24,7 @@ import {
makeGenerateCombinedPost,
extractUserActivityData,
START_OF_NEW_MESSAGES,
shouldShowJoinLeaveMessages,
} from './post_list';
describe('makeFilterPostsAndAddSeparators', () => {
@@ -35,7 +36,9 @@ describe('makeFilterPostsAndAddSeparators', () => {
let state = {
entities: {
general: {
config: {},
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
posts: {
posts: {
@@ -1472,3 +1475,95 @@ describe('combineUserActivityData', () => {
expect(combineUserActivitySystemPost(posts)).toEqual(expectedOutput);
});
});
describe('shouldShowJoinLeaveMessages', () => {
it('should default to true', () => {
const state = {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
preferences: {
myPreferences: {},
},
},
} as unknown as GlobalState;
// Defaults to show post
const show = shouldShowJoinLeaveMessages(state);
expect(show).toEqual(true);
});
it('set config to false, return false', () => {
const state = {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'false',
},
},
preferences: {
myPreferences: {},
},
},
} as unknown as GlobalState;
// Defaults to show post
const show = shouldShowJoinLeaveMessages(state);
expect(show).toEqual(false);
});
it('if user preference, set default wont be used', () => {
const state = {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'false',
},
},
preferences: {
myPreferences: {
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
value: 'true',
},
},
},
},
} as unknown as GlobalState;
// Defaults to show post
const show = shouldShowJoinLeaveMessages(state);
expect(show).toEqual(true);
});
it('if user preference, set default wont be used', () => {
const state = {
entities: {
general: {
config: {
EnableJoinLeaveMessageByDefault: 'true',
},
},
preferences: {
myPreferences: {
[getPreferenceKey(Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE)]: {
category: Preferences.CATEGORY_ADVANCED_SETTINGS,
name: Preferences.ADVANCED_FILTER_JOIN_LEAVE,
value: 'false',
},
},
},
},
} as unknown as GlobalState;
// Defaults to show post
const show = shouldShowJoinLeaveMessages(state);
expect(show).toEqual(false);
});
});

Просмотреть файл

@@ -10,6 +10,7 @@ import {makeGetPostsForIds, UserActivityPost} from 'mattermost-redux/selectors/e
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {createIdsSelector, memoizeResult} from 'mattermost-redux/utils/helpers';
import {isUserActivityPost, shouldFilterJoinLeavePost, isFromWebhook} from 'mattermost-redux/utils/post_utils';
@@ -25,8 +26,11 @@ export const START_OF_NEW_MESSAGES = 'start-of-new-messages';
export const MAX_COMBINED_SYSTEM_POSTS = 100;
export function shouldShowJoinLeaveMessages(state: GlobalState) {
const config = getConfig(state);
const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true';
// This setting is true or not set if join/leave messages are to be displayed
return getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE, true);
return getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_FILTER_JOIN_LEAVE, enableJoinLeaveMessage);
}
interface PostFilterOptions {

Просмотреть файл

@@ -70,6 +70,7 @@ export type ClientConfig = {
EnableGifPicker: string;
EnableGuestAccounts: string;
EnableIncomingWebhooks: string;
EnableJoinLeaveMessageByDefault: string;
EnableLatex: string;
EnableInlineLatex: string;
EnableLdap: string;