mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
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>
This commit is contained in:
parent
fe4a77498a
commit
f35291169c
@ -23,6 +23,7 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li
|
||||
props["LockTeammateNameDisplay"] = strconv.FormatBool(*c.TeamSettings.LockTeammateNameDisplay)
|
||||
props["ExperimentalPrimaryTeam"] = *c.TeamSettings.ExperimentalPrimaryTeam
|
||||
props["ExperimentalViewArchivedChannels"] = strconv.FormatBool(*c.TeamSettings.ExperimentalViewArchivedChannels)
|
||||
props["EnableJoinLeaveMessageByDefault"] = strconv.FormatBool(*c.TeamSettings.EnableJoinLeaveMessageByDefault)
|
||||
|
||||
props["EnableBotAccountCreation"] = strconv.FormatBool(*c.ServiceSettings.EnableBotAccountCreation)
|
||||
props["EnableOAuthServiceProvider"] = strconv.FormatBool(*c.ServiceSettings.EnableOAuthServiceProvider)
|
||||
@ -241,6 +242,7 @@ func GenerateLimitedClientConfig(c *model.Config, telemetryID string, license *m
|
||||
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
|
||||
props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
|
||||
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
|
||||
props["EnableJoinLeaveMessageByDefault"] = strconv.FormatBool(*c.TeamSettings.EnableJoinLeaveMessageByDefault)
|
||||
|
||||
props["AndroidLatestVersion"] = c.ClientRequirements.AndroidLatestVersion
|
||||
props["AndroidMinVersion"] = c.ClientRequirements.AndroidMinVersion
|
||||
|
@ -271,6 +271,28 @@ func TestGetClientConfig(t *testing.T) {
|
||||
"DisableAppBar": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
"default EnableJoinLeaveMessage",
|
||||
&model.Config{},
|
||||
"tag1",
|
||||
nil,
|
||||
map[string]string{
|
||||
"EnableJoinLeaveMessageByDefault": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
"disable EnableJoinLeaveMessage",
|
||||
&model.Config{
|
||||
TeamSettings: model.TeamSettings{
|
||||
EnableJoinLeaveMessageByDefault: model.NewBool(false),
|
||||
},
|
||||
},
|
||||
"tag1",
|
||||
nil,
|
||||
map[string]string{
|
||||
"EnableJoinLeaveMessageByDefault": "false",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
|
@ -2129,18 +2129,19 @@ func (s *ThemeSettings) SetDefaults() {
|
||||
}
|
||||
|
||||
type TeamSettings struct {
|
||||
SiteName *string `access:"site_customization"`
|
||||
MaxUsersPerTeam *int `access:"site_users_and_teams"`
|
||||
EnableUserCreation *bool `access:"authentication_signup"`
|
||||
EnableOpenServer *bool `access:"authentication_signup"`
|
||||
EnableUserDeactivation *bool `access:"experimental_features"`
|
||||
RestrictCreationToDomains *string `access:"authentication_signup"` // telemetry: none
|
||||
EnableCustomUserStatuses *bool `access:"site_users_and_teams"`
|
||||
EnableCustomBrand *bool `access:"site_customization"`
|
||||
CustomBrandText *string `access:"site_customization"`
|
||||
CustomDescriptionText *string `access:"site_customization"`
|
||||
RestrictDirectMessage *string `access:"site_users_and_teams"`
|
||||
EnableLastActiveTime *bool `access:"site_users_and_teams"`
|
||||
SiteName *string `access:"site_customization"`
|
||||
MaxUsersPerTeam *int `access:"site_users_and_teams"`
|
||||
EnableJoinLeaveMessageByDefault *bool `access:"site_users_and_teams"`
|
||||
EnableUserCreation *bool `access:"authentication_signup"`
|
||||
EnableOpenServer *bool `access:"authentication_signup"`
|
||||
EnableUserDeactivation *bool `access:"experimental_features"`
|
||||
RestrictCreationToDomains *string `access:"authentication_signup"` // telemetry: none
|
||||
EnableCustomUserStatuses *bool `access:"site_users_and_teams"`
|
||||
EnableCustomBrand *bool `access:"site_customization"`
|
||||
CustomBrandText *string `access:"site_customization"`
|
||||
CustomDescriptionText *string `access:"site_customization"`
|
||||
RestrictDirectMessage *string `access:"site_users_and_teams"`
|
||||
EnableLastActiveTime *bool `access:"site_users_and_teams"`
|
||||
// In seconds.
|
||||
UserStatusAwayTimeout *int64 `access:"experimental_features"`
|
||||
MaxChannelsPerTeam *int64 `access:"site_users_and_teams"`
|
||||
@ -2164,6 +2165,10 @@ func (s *TeamSettings) SetDefaults() {
|
||||
s.MaxUsersPerTeam = NewInt(TeamSettingsDefaultMaxUsersPerTeam)
|
||||
}
|
||||
|
||||
if s.EnableJoinLeaveMessageByDefault == nil {
|
||||
s.EnableJoinLeaveMessageByDefault = NewBool(true)
|
||||
}
|
||||
|
||||
if s.EnableUserCreation == nil {
|
||||
s.EnableUserCreation = NewBool(true)
|
||||
}
|
||||
|
@ -335,6 +335,14 @@ func TestTeamSettingsIsValidSiteNameEmpty(t *testing.T) {
|
||||
require.Nil(t, c1.TeamSettings.isValid())
|
||||
}
|
||||
|
||||
func TestTeamSettingsDefaultJoinLeaveMessage(t *testing.T) {
|
||||
c1 := Config{}
|
||||
c1.SetDefaults()
|
||||
|
||||
// should default to true
|
||||
require.Equal(t, NewBool(true), c1.TeamSettings.EnableJoinLeaveMessageByDefault)
|
||||
}
|
||||
|
||||
func TestMessageExportSettingsIsValidEnableExportNotSet(t *testing.T) {
|
||||
mes := &MessageExportSettings{}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user