Move config to its own database table (#6744)
* Move config to its own database table * Address feedback * Fix test * Revert minimum version related changes
This commit is contained in:
parent
887565423c
commit
1aa4188f8e
85 changed files with 562 additions and 403 deletions
|
|
@ -15,7 +15,7 @@ import {
|
|||
getMyChannel, getChannelById, queryUsersOnChannel, queryUserChannelsByTypes,
|
||||
} from '@queries/servers/channel';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {prepareCommonSystemValues, PrepareCommonSystemValuesArgs, getCommonSystemValues, getCurrentTeamId, setCurrentChannelId, getCurrentUserId} from '@queries/servers/system';
|
||||
import {prepareCommonSystemValues, PrepareCommonSystemValuesArgs, getCommonSystemValues, getCurrentTeamId, setCurrentChannelId, getCurrentUserId, getConfig, getLicense} from '@queries/servers/system';
|
||||
import {addChannelToTeamHistory, addTeamToTeamHistory, getTeamById, removeChannelFromTeamHistory} from '@queries/servers/team';
|
||||
import {getCurrentUser, queryUsersById} from '@queries/servers/user';
|
||||
import {dismissAllModalsAndPopToRoot, dismissAllModalsAndPopToScreen} from '@screens/navigation';
|
||||
|
|
@ -365,9 +365,10 @@ export async function updateChannelsDisplayName(serverUrl: string, channels: Cha
|
|||
return {};
|
||||
}
|
||||
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT).fetch();
|
||||
const displaySettings = getTeammateNameDisplaySetting(preferences, config, license);
|
||||
const displaySettings = getTeammateNameDisplaySetting(preferences, config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
const models: Model[] = [];
|
||||
for await (const channel of channels) {
|
||||
let newDisplayName = '';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import deepEqual from 'deep-equal';
|
|||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getServerCredentials} from '@init/credentials';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {getConfig, getLicense} from '@queries/servers/system';
|
||||
import {logError} from '@utils/log';
|
||||
|
||||
export async function storeConfigAndLicense(serverUrl: string, config: ClientConfig, license: ClientLicense) {
|
||||
|
|
@ -14,17 +14,11 @@ export async function storeConfigAndLicense(serverUrl: string, config: ClientCon
|
|||
// If we have credentials for this server then update the values in the database
|
||||
const credentials = await getServerCredentials(serverUrl);
|
||||
if (credentials) {
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const current = await getCommonSystemValues(operator.database);
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const currentLicense = await getLicense(database);
|
||||
const systems: IdValue[] = [];
|
||||
if (!deepEqual(config, current.config)) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.CONFIG,
|
||||
value: JSON.stringify(config),
|
||||
});
|
||||
}
|
||||
|
||||
if (!deepEqual(license, current.license)) {
|
||||
if (!deepEqual(license, currentLicense)) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.LICENSE,
|
||||
value: JSON.stringify(license),
|
||||
|
|
@ -34,8 +28,43 @@ export async function storeConfigAndLicense(serverUrl: string, config: ClientCon
|
|||
if (systems.length) {
|
||||
await operator.handleSystem({systems, prepareRecordsOnly: false});
|
||||
}
|
||||
|
||||
await storeConfig(serverUrl, config);
|
||||
}
|
||||
} catch (error) {
|
||||
logError('An error occurred while saving config & license', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function storeConfig(serverUrl: string, config: ClientConfig | undefined, prepareRecordsOnly = false) {
|
||||
if (!config) {
|
||||
return [];
|
||||
}
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const currentConfig = await getConfig(database);
|
||||
const configsToUpdate: IdValue[] = [];
|
||||
const configsToDelete: IdValue[] = [];
|
||||
|
||||
let k: keyof ClientConfig;
|
||||
for (k in config) {
|
||||
if (currentConfig?.[k] !== config[k]) {
|
||||
configsToUpdate.push({
|
||||
id: k,
|
||||
value: config[k],
|
||||
});
|
||||
}
|
||||
}
|
||||
for (k in currentConfig) {
|
||||
if (config[k] === undefined) {
|
||||
configsToDelete.push({
|
||||
id: k,
|
||||
value: currentConfig[k],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (configsToDelete.length || configsToUpdate.length) {
|
||||
return operator.handleConfigs({configs: configsToUpdate, configsToDelete, prepareRecordsOnly});
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import DatabaseManager from '@database/manager';
|
|||
import {getTranslations, t} from '@i18n';
|
||||
import {getChannelById} from '@queries/servers/channel';
|
||||
import {getPostById} from '@queries/servers/post';
|
||||
import {getCommonSystemValues, getCurrentTeamId, getCurrentUserId, prepareCommonSystemValues, PrepareCommonSystemValuesArgs, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {getCurrentTeamId, getCurrentUserId, prepareCommonSystemValues, PrepareCommonSystemValuesArgs, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {addChannelToTeamHistory, addTeamToTeamHistory} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled, getThreadById, prepareThreadsFromReceivedPosts, queryThreadsInTeam} from '@queries/servers/thread';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
|
|
@ -74,12 +74,12 @@ export const switchToThread = async (serverUrl: string, rootId: string, isFromNo
|
|||
throw new Error('Channel not found');
|
||||
}
|
||||
|
||||
const system = await getCommonSystemValues(database);
|
||||
const currentTeamId = await getCurrentTeamId(database);
|
||||
const isTabletDevice = await isTablet();
|
||||
const teamId = channel.teamId || system.currentTeamId;
|
||||
const teamId = channel.teamId || currentTeamId;
|
||||
|
||||
let switchingTeams = false;
|
||||
if (system.currentTeamId !== teamId) {
|
||||
if (currentTeamId !== teamId) {
|
||||
const modelPromises: Array<Promise<Model[]>> = [];
|
||||
switchingTeams = true;
|
||||
modelPromises.push(addTeamToTeamHistory(operator, teamId, true));
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ export async function fetchDirectChannelsInfo(serverUrl: string, directChannels:
|
|||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).fetch();
|
||||
const config = await getConfig(database);
|
||||
const license = await getLicense(database);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences, config, license);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences, config?.LockTeammateNameDisplay, config?.TeammateNameDisplay, license);
|
||||
const currentUser = await getCurrentUser(database);
|
||||
const channels = directChannels.map((d) => d.toApi());
|
||||
return fetchMissingDirectChannelsInfo(serverUrl, channels, currentUser?.locale, teammateDisplayNameSetting, currentUser?.id);
|
||||
|
|
@ -743,8 +743,9 @@ export async function createDirectChannel(serverUrl: string, userId: string, dis
|
|||
created.display_name = displayName;
|
||||
} else {
|
||||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT).fetch();
|
||||
const system = await getCommonSystemValues(database);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], system.config, system.license);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
const {directChannels, users} = await fetchMissingDirectChannelsInfo(serverUrl, [created], currentUser.locale, teammateDisplayNameSetting, currentUser.id, true);
|
||||
created.display_name = directChannels?.[0].display_name || created.display_name;
|
||||
if (users?.length) {
|
||||
|
|
@ -860,19 +861,16 @@ export async function fetchArchivedChannels(serverUrl: string, teamId: string, p
|
|||
}
|
||||
|
||||
export async function createGroupChannel(serverUrl: string, userIds: string[]) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
let client: Client;
|
||||
try {
|
||||
client = NetworkManager.getClient(serverUrl);
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
|
||||
try {
|
||||
const currentUser = await getCurrentUser(operator.database);
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const currentUser = await getCurrentUser(database);
|
||||
if (!currentUser) {
|
||||
return {error: 'Cannot get the current user'};
|
||||
}
|
||||
|
|
@ -886,9 +884,10 @@ export async function createGroupChannel(serverUrl: string, userIds: string[]) {
|
|||
return {data: created};
|
||||
}
|
||||
|
||||
const preferences = await queryPreferencesByCategoryAndName(operator.database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT).fetch();
|
||||
const system = await getCommonSystemValues(operator.database);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], system.config, system.license);
|
||||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT).fetch();
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
const {directChannels, users} = await fetchMissingDirectChannelsInfo(serverUrl, [created], currentUser.locale, teammateDisplayNameSetting, currentUser.id, true);
|
||||
|
||||
const member = {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {prepareCommonSystemValues, getCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, setCurrentTeamAndChannelId, getCurrentChannelId} from '@queries/servers/system';
|
||||
import {prepareCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, setCurrentTeamAndChannelId, getCurrentChannelId, getConfig, getLicense} from '@queries/servers/system';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {deleteV1Data} from '@utils/file';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
|
|
@ -65,7 +65,8 @@ export async function appEntry(serverUrl: string, since = 0, isUpgrade = false)
|
|||
logInfo('ENTRY MODELS BATCHING TOOK', `${Date.now() - dt}ms`);
|
||||
|
||||
const {id: currentUserId, locale: currentUserLocale} = meData?.user || (await getCurrentUser(database))!;
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
const config = await getConfig(database);
|
||||
const license = await getLicense(database);
|
||||
await deferredAppEntryActions(serverUrl, lastDisconnectedAt, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, initialTeamId, switchToChannel ? initialChannelId : undefined);
|
||||
|
||||
if (!since) {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ export const fetchAppEntryData = async (serverUrl: string, sinceArg: number, ini
|
|||
|
||||
const confReq = await fetchConfigAndLicense(serverUrl);
|
||||
const prefData = await fetchMyPreferences(serverUrl, fetchOnly);
|
||||
const isCRTEnabled = Boolean(prefData.preferences && processIsCRTEnabled(prefData.preferences, confReq.config));
|
||||
const isCRTEnabled = Boolean(prefData.preferences && processIsCRTEnabled(prefData.preferences, confReq.config?.CollapsedThreads, confReq.config?.FeatureFlagCollapsedThreads));
|
||||
if (prefData.preferences) {
|
||||
const crtToggled = await getHasCRTChanged(database, prefData.preferences);
|
||||
if (crtToggled) {
|
||||
|
|
@ -306,7 +306,7 @@ export async function entryInitialChannelId(database: Database, requestedChannel
|
|||
|
||||
export async function restDeferredAppEntryActions(
|
||||
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig, license: ClientLicense, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
config: ClientConfig, license: ClientLicense | undefined, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
initialTeamId?: string, initialChannelId?: string) {
|
||||
// defer sidebar DM & GM profiles
|
||||
let channelsToFetchProfiles: Set<Channel>|undefined;
|
||||
|
|
@ -325,7 +325,7 @@ export async function restDeferredAppEntryActions(
|
|||
fetchTeamsChannelsAndUnreadPosts(serverUrl, since, teamData.teams, teamData.memberships, initialTeamId);
|
||||
}
|
||||
|
||||
if (preferences && processIsCRTEnabled(preferences, config)) {
|
||||
if (preferences && processIsCRTEnabled(preferences, config.CollapsedThreads, config.FeatureFlagCollapsedThreads)) {
|
||||
if (initialTeamId) {
|
||||
await fetchNewThreads(serverUrl, initialTeamId, false);
|
||||
}
|
||||
|
|
@ -348,7 +348,7 @@ export async function restDeferredAppEntryActions(
|
|||
|
||||
setTimeout(async () => {
|
||||
if (channelsToFetchProfiles?.size) {
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config, license);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
fetchMissingDirectChannelsInfo(serverUrl, Array.from(channelsToFetchProfiles), currentUserLocale, teammateDisplayNameSetting, currentUserId);
|
||||
}
|
||||
}, FETCH_MISSING_DM_TIMEOUT);
|
||||
|
|
@ -454,7 +454,7 @@ const restSyncAllChannelMembers = async (serverUrl: string) => {
|
|||
for (const myTeam of myTeams) {
|
||||
fetchMyChannelsForTeam(serverUrl, myTeam.id, false, 0, false, excludeDirect);
|
||||
excludeDirect = true;
|
||||
if (preferences && processIsCRTEnabled(preferences, config)) {
|
||||
if (preferences && processIsCRTEnabled(preferences, config.CollapsedThreads, config.FeatureFlagCollapsedThreads)) {
|
||||
fetchNewThreads(serverUrl, myTeam.id, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export async function deferredAppEntryGraphQLActions(
|
|||
}
|
||||
}, FETCH_UNREADS_TIMEOUT);
|
||||
|
||||
if (preferences && processIsCRTEnabled(preferences, config)) {
|
||||
if (preferences && processIsCRTEnabled(preferences, config.CollapsedThreads, config.FeatureFlagCollapsedThreads)) {
|
||||
if (initialTeamId) {
|
||||
await fetchNewThreads(serverUrl, initialTeamId, false);
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ export const entry = async (serverUrl: string, teamId?: string, channelId?: stri
|
|||
|
||||
export async function deferredAppEntryActions(
|
||||
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig, license: ClientLicense, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
config: ClientConfig, license: ClientLicense | undefined, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
initialTeamId?: string, initialChannelId?: string) {
|
||||
let result;
|
||||
if (config?.FeatureFlagGraphQL === 'true') {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {getDefaultThemeByAppearance} from '@context/theme';
|
|||
import DatabaseManager from '@database/manager';
|
||||
import {getMyChannel} from '@queries/servers/channel';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {getCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {getConfig, getCurrentTeamId, getLicense, getWebSocketLastDisconnected, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {getMyTeamById} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
|
|
@ -136,7 +136,8 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
await operator.batchRecords(models);
|
||||
|
||||
const {id: currentUserId, locale: currentUserLocale} = (await getCurrentUser(operator.database))!;
|
||||
const {config, license} = await getCommonSystemValues(operator.database);
|
||||
const config = await getConfig(database);
|
||||
const license = await getLicense(database);
|
||||
|
||||
await deferredAppEntryActions(serverUrl, lastDisconnectedAt, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, selectedTeamId, selectedChannelId);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {fetchMyTeam} from '@actions/remote/team';
|
|||
import {fetchAndSwitchToThread} from '@actions/remote/thread';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getMyChannel, getChannelById} from '@queries/servers/channel';
|
||||
import {getCommonSystemValues, getWebSocketLastDisconnected} from '@queries/servers/system';
|
||||
import {getCurrentTeamId, getWebSocketLastDisconnected} from '@queries/servers/system';
|
||||
import {getMyTeamById} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {emitNotificationError} from '@utils/notification';
|
||||
|
|
@ -30,14 +30,14 @@ const fetchNotificationData = async (serverUrl: string, notification: Notificati
|
|||
}
|
||||
|
||||
const {database} = operator;
|
||||
const system = await getCommonSystemValues(database);
|
||||
const currentTeamId = await getCurrentTeamId(database);
|
||||
let teamId = notification.payload?.team_id;
|
||||
let isDirectChannel = false;
|
||||
|
||||
if (!teamId) {
|
||||
// If the notification payload does not have a teamId we assume is a DM/GM
|
||||
isDirectChannel = true;
|
||||
teamId = system.currentTeamId;
|
||||
teamId = currentTeamId;
|
||||
}
|
||||
|
||||
// To make the switch faster we determine if we already have the team & channel
|
||||
|
|
@ -129,13 +129,13 @@ export const openNotification = async (serverUrl: string, notification: Notifica
|
|||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
const isThreadNotification = isCRTEnabled && Boolean(rootId);
|
||||
|
||||
const system = await getCommonSystemValues(database);
|
||||
const currentTeamId = await getCurrentTeamId(database);
|
||||
const currentServerUrl = await DatabaseManager.getActiveServerUrl();
|
||||
let teamId = notification.payload?.team_id;
|
||||
|
||||
if (!teamId) {
|
||||
// If the notification payload does not have a teamId we assume is a DM/GM
|
||||
teamId = system.currentTeamId;
|
||||
teamId = currentTeamId;
|
||||
}
|
||||
|
||||
if (currentServerUrl !== serverUrl) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {storeConfig} from '@actions/local/systems';
|
||||
import {Preferences} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getPreferenceValue, getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
|
|
@ -9,7 +10,7 @@ import NetworkManager from '@managers/network_manager';
|
|||
import {prepareCategories, prepareCategoryChannels} from '@queries/servers/categories';
|
||||
import {prepareMyChannelsForTeam} from '@queries/servers/channel';
|
||||
import {prepareMyPreferences, queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {prepareCommonSystemValues, getCommonSystemValues} from '@queries/servers/system';
|
||||
import {prepareCommonSystemValues, getConfig, getLicense} from '@queries/servers/system';
|
||||
import {prepareMyTeams} from '@queries/servers/team';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {isDMorGM, selectDefaultChannelForTeam} from '@utils/channel';
|
||||
|
|
@ -101,14 +102,15 @@ export async function retryInitialTeamAndChannel(serverUrl: string) {
|
|||
|
||||
const models: Model[] = (await Promise.all([
|
||||
prepareMyPreferences(operator, prefData.preferences!),
|
||||
storeConfig(serverUrl, clData.config, true),
|
||||
...prepareMyTeams(operator, teamData.teams!, teamData.memberships!),
|
||||
...await prepareMyChannelsForTeam(operator, initialTeam.id, chData!.channels!, chData!.memberships!),
|
||||
prepareCategories(operator, chData!.categories!),
|
||||
prepareCategoryChannels(operator, chData!.categories!),
|
||||
|
||||
prepareCommonSystemValues(
|
||||
operator,
|
||||
{
|
||||
config: clData.config!,
|
||||
license: clData.license!,
|
||||
currentTeamId: initialTeam?.id,
|
||||
currentChannelId: initialChannel?.id,
|
||||
|
|
@ -121,7 +123,7 @@ export async function retryInitialTeamAndChannel(serverUrl: string) {
|
|||
const directChannels = chData!.channels!.filter(isDMorGM);
|
||||
const channelsToFetchProfiles = new Set<Channel>(directChannels);
|
||||
if (channelsToFetchProfiles.size) {
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(prefData.preferences || [], clData.config, clData.license);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(prefData.preferences || [], clData.config?.LockTeammateNameDisplay, clData.config?.TeammateNameDisplay, clData.license);
|
||||
fetchMissingDirectChannelsInfo(serverUrl, Array.from(channelsToFetchProfiles), user.locale, teammateDisplayNameSetting, user.id);
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +165,8 @@ export async function retryInitialChannel(serverUrl: string, teamId: string) {
|
|||
user_id: p.userId,
|
||||
value: p.value,
|
||||
}));
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
|
||||
// fetch channels / channel membership for initial team
|
||||
const chData = await fetchMyChannelsForTeam(serverUrl, teamId, false, 0, true);
|
||||
|
|
@ -200,7 +203,7 @@ export async function retryInitialChannel(serverUrl: string, teamId: string) {
|
|||
const directChannels = chData!.channels!.filter(isDMorGM);
|
||||
const channelsToFetchProfiles = new Set<Channel>(directChannels);
|
||||
if (channelsToFetchProfiles.size) {
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config, license);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
fetchMissingDirectChannelsInfo(serverUrl, Array.from(channelsToFetchProfiles), user.locale, teammateDisplayNameSetting, user.id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import NetworkManager from '@managers/network_manager';
|
|||
import WebsocketManager from '@managers/websocket_manager';
|
||||
import {getDeviceToken} from '@queries/app/global';
|
||||
import {queryServerName} from '@queries/app/servers';
|
||||
import {getCurrentUserId, getCommonSystemValues, getExpiredSession} from '@queries/servers/system';
|
||||
import {getCurrentUserId, getExpiredSession, getConfig, getLicense} from '@queries/servers/system';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import {logWarning, logError} from '@utils/log';
|
||||
|
|
@ -35,9 +35,10 @@ export const completeLogin = async (serverUrl: string) => {
|
|||
}
|
||||
|
||||
const {database} = operator;
|
||||
const {config, license}: { config: Partial<ClientConfig>; license: Partial<ClientLicense> } = await getCommonSystemValues(database);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
|
||||
if (!Object.keys(config)?.length || !Object.keys(license)?.length) {
|
||||
if (!Object.keys(config)?.length || !license || !Object.keys(license)?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import PushNotifications from '@init/push_notifications';
|
|||
import AppsManager from '@managers/apps_manager';
|
||||
import NetworkManager from '@managers/network_manager';
|
||||
import {getPostById} from '@queries/servers/post';
|
||||
import {getCommonSystemValues, getCurrentChannelId, getCurrentTeamId} from '@queries/servers/system';
|
||||
import {getConfigValue, getCurrentChannelId, getCurrentTeamId} from '@queries/servers/system';
|
||||
import {getIsCRTEnabled, getNewestThreadInTeam, getThreadById} from '@queries/servers/thread';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
|
||||
|
|
@ -104,9 +104,8 @@ export const fetchThreads = async (
|
|||
}
|
||||
|
||||
try {
|
||||
const {config} = await getCommonSystemValues(database);
|
||||
|
||||
const data = await client.getThreads('me', teamId, before, after, perPage, deleted, unread, since, false, config.Version);
|
||||
const version = await getConfigValue(database, 'Version');
|
||||
const data = await client.getThreads('me', teamId, before, after, perPage, deleted, unread, since, false, version);
|
||||
|
||||
const {threads} = data;
|
||||
|
||||
|
|
@ -323,7 +322,7 @@ async function fetchBatchThreads(
|
|||
return {error: 'currentUser not found'};
|
||||
}
|
||||
|
||||
const {config} = await getCommonSystemValues(operator.database);
|
||||
const version = await getConfigValue(operator.database, 'Version');
|
||||
const data: Thread[] = [];
|
||||
|
||||
const fetchThreadsFunc = async (opts: FetchThreadsOptions) => {
|
||||
|
|
@ -331,7 +330,7 @@ async function fetchBatchThreads(
|
|||
const {before, after, perPage = General.CRT_CHUNK_SIZE, deleted, unread, since} = opts;
|
||||
|
||||
page += 1;
|
||||
const {threads} = await client.getThreads(currentUser.id, teamId, before, after, perPage, deleted, unread, since, false, config.Version);
|
||||
const {threads} = await client.getThreads(currentUser.id, teamId, before, after, perPage, deleted, unread, since, false, version);
|
||||
if (threads.length) {
|
||||
// Mark all fetched threads as following
|
||||
for (const thread of threads) {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {fetchGroupsForChannel, fetchGroupsForMember, fetchGroupsForTeam} from '@actions/remote/groups';
|
||||
import {deleteGroupChannelById, deleteGroupMembershipById, deleteGroupTeamById} from '@app/queries/servers/group';
|
||||
import {generateGroupAssociationId} from '@app/utils/groups';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {deleteGroupChannelById, deleteGroupMembershipById, deleteGroupTeamById} from '@queries/servers/group';
|
||||
import {generateGroupAssociationId} from '@utils/groups';
|
||||
import {logError} from '@utils/log';
|
||||
|
||||
type WebsocketGroupMessage = WebSocketMessage<{
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ import AppsManager from '@managers/apps_manager';
|
|||
import {getActiveServerUrl, queryActiveServer} from '@queries/app/servers';
|
||||
import {getCurrentChannel} from '@queries/servers/channel';
|
||||
import {
|
||||
getCommonSystemValues,
|
||||
getConfig,
|
||||
getCurrentUserId,
|
||||
getLicense,
|
||||
getWebSocketLastDisconnected,
|
||||
resetWebSocketLastDisconnected,
|
||||
setCurrentTeamAndChannelId,
|
||||
|
|
@ -178,7 +178,8 @@ async function doReconnect(serverUrl: string) {
|
|||
logInfo('WEBSOCKET RECONNECT MODELS BATCHING TOOK', `${Date.now() - dt}ms`);
|
||||
|
||||
const {id: currentUserId, locale: currentUserLocale} = (await getCurrentUser(database))!;
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
|
||||
if (isSupportedServerCalls(config?.Version)) {
|
||||
loadConfigAndCalls(serverUrl, currentUserId);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {updateDmGmDisplayName} from '@actions/local/channel';
|
||||
import {storeConfig} from '@actions/local/systems';
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getConfig, getLicense} from '@queries/servers/system';
|
||||
|
|
@ -35,10 +36,8 @@ export async function handleConfigChangedEvent(serverUrl: string, msg: WebSocket
|
|||
|
||||
try {
|
||||
const config = msg.data.config;
|
||||
const systems: IdValue[] = [{id: SYSTEM_IDENTIFIERS.CONFIG, value: JSON.stringify(config)}];
|
||||
|
||||
const prevConfig = await getConfig(operator.database);
|
||||
await operator.handleSystem({systems, prepareRecordsOnly: false});
|
||||
await storeConfig(serverUrl, config);
|
||||
if (config?.LockTeammateNameDisplay && (prevConfig?.LockTeammateNameDisplay !== config.LockTeammateNameDisplay)) {
|
||||
updateDmGmDisplayName(serverUrl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
|||
import WebsocketManager from '@managers/websocket_manager';
|
||||
import {queryChannelsByTypes, queryUserChannelsByTypes} from '@queries/servers/channel';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {getConfig, getLicense} from '@queries/servers/system';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {displayUsername} from '@utils/user';
|
||||
|
||||
|
|
@ -84,13 +84,14 @@ export async function handleUserTypingEvent(serverUrl: string, msg: WebSocketMes
|
|||
return;
|
||||
}
|
||||
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
|
||||
const {users, existingUsers} = await fetchUsersByIds(serverUrl, [msg.data.user_id]);
|
||||
const user = users?.[0] || existingUsers?.[0];
|
||||
|
||||
const namePreference = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT).fetch();
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(namePreference, config, license);
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(namePreference, config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
const currentUser = await getCurrentUser(database);
|
||||
const username = displayUsername(user, currentUser?.locale, teammateDisplayNameSetting);
|
||||
const data = {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {Platform} from 'react-native';
|
|||
|
||||
import {WebsocketEvents} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {getConfig} from '@queries/servers/system';
|
||||
import {logError, logInfo, logWarning} from '@utils/log';
|
||||
|
||||
const MAX_WEBSOCKET_FAILS = 7;
|
||||
|
|
@ -75,8 +75,8 @@ export default class WebSocketClient {
|
|||
return;
|
||||
}
|
||||
|
||||
const system = await getCommonSystemValues(database);
|
||||
const connectionUrl = (system.config.WebsocketURL || this.serverUrl) + '/api/v4/websocket';
|
||||
const config = await getConfig(database);
|
||||
const connectionUrl = (config.WebsocketURL || this.serverUrl) + '/api/v4/websocket';
|
||||
|
||||
if (this.connectingCallback) {
|
||||
this.connectingCallback();
|
||||
|
|
@ -97,7 +97,7 @@ export default class WebSocketClient {
|
|||
|
||||
this.url = connectionUrl;
|
||||
|
||||
const reliableWebSockets = system.config.EnableReliableWebSockets === 'true';
|
||||
const reliableWebSockets = config.EnableReliableWebSockets === 'true';
|
||||
if (reliableWebSockets) {
|
||||
// Add connection id, and last_sequence_number to the query param.
|
||||
// We cannot also send it as part of the auth_challenge, because the session cookie is already sent with the request.
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue} from '@queries/servers/system';
|
||||
import {observeUser} from '@queries/servers/user';
|
||||
import {getUserCustomStatus, isCustomStatusExpired} from '@utils/user';
|
||||
|
||||
|
|
@ -21,9 +21,8 @@ type HeaderInputProps = {
|
|||
const enhanced = withObservables(
|
||||
['userId'],
|
||||
({userId, database}: WithDatabaseArgs & HeaderInputProps) => {
|
||||
const config = observeConfig(database);
|
||||
const user = observeUser(database, userId);
|
||||
const isCustomStatusEnabled = config.pipe(map((cfg) => cfg?.EnableCustomUserStatuses === 'true'));
|
||||
const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses');
|
||||
const customStatus = user.pipe(switchMap((u) => (u?.isBot ? of$(undefined) : of$(getUserCustomStatus(u)))));
|
||||
const customStatusExpired = user.pipe(switchMap((u) => (u?.isBot ? of$(false) : of$(isCustomStatusExpired(u)))));
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import withObservables from '@nozbe/with-observables';
|
|||
import {combineLatest, of as of$, from as from$} from 'rxjs';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig, observeLicense} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeLicense} from '@queries/servers/system';
|
||||
import {fileExists} from '@utils/file';
|
||||
|
||||
import Files from './files';
|
||||
|
|
@ -36,14 +36,8 @@ const filesLocalPathValidation = async (files: FileModel[], authorId: string) =>
|
|||
};
|
||||
|
||||
const enhance = withObservables(['post'], ({database, post}: EnhanceProps) => {
|
||||
const config = observeConfig(database);
|
||||
const enableMobileFileDownload = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.EnableMobileFileDownload !== 'false')),
|
||||
);
|
||||
|
||||
const publicLinkEnabled = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.EnablePublicLink !== 'false')),
|
||||
);
|
||||
const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload');
|
||||
const publicLinkEnabled = observeConfigBooleanValue(database, 'EnablePublicLink');
|
||||
|
||||
const complianceDisabled = observeLicense(database).pipe(
|
||||
switchMap((lcs) => of$(lcs?.IsLicensed === 'false' || lcs?.Compliance === 'false')),
|
||||
|
|
|
|||
|
|
@ -4,19 +4,16 @@
|
|||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue} from '@queries/servers/system';
|
||||
|
||||
import Markdown from './markdown';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const enableLatex = config.pipe(switchMap((c) => of$(c?.EnableLatex === 'true')));
|
||||
const enableInlineLatex = config.pipe(switchMap((c) => of$(c?.EnableInlineLatex === 'true')));
|
||||
const enableLatex = observeConfigBooleanValue(database, 'EnableLatex');
|
||||
const enableInlineLatex = observeConfigBooleanValue(database, 'EnableInlineLatex');
|
||||
|
||||
return {
|
||||
enableLatex,
|
||||
|
|
|
|||
|
|
@ -3,23 +3,16 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigValue} from '@queries/servers/system';
|
||||
|
||||
import MarkdownLink from './markdown_link';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhance = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const experimentalNormalizeMarkdownLinks = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.ExperimentalNormalizeMarkdownLinks)),
|
||||
);
|
||||
const siteURL = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.SiteURL)),
|
||||
);
|
||||
const experimentalNormalizeMarkdownLinks = observeConfigValue(database, 'ExperimentalNormalizeMarkdownLinks');
|
||||
const siteURL = observeConfigValue(database, 'SiteURL');
|
||||
|
||||
return {
|
||||
experimentalNormalizeMarkdownLinks,
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ type Props = {
|
|||
cursorPosition: number;
|
||||
rootId?: string;
|
||||
files?: FileInfo[];
|
||||
maxFileSize: number;
|
||||
maxFileCount: number;
|
||||
maxFileSize: number;
|
||||
canUploadFiles: boolean;
|
||||
updateCursorPosition: React.Dispatch<React.SetStateAction<number>>;
|
||||
updatePostInputTop: (top: number) => void;
|
||||
|
|
@ -41,8 +41,8 @@ export default function DraftHandler(props: Props) {
|
|||
cursorPosition,
|
||||
rootId = '',
|
||||
files,
|
||||
maxFileSize,
|
||||
maxFileCount,
|
||||
maxFileSize,
|
||||
canUploadFiles,
|
||||
updateCursorPosition,
|
||||
updatePostInputTop,
|
||||
|
|
@ -106,7 +106,7 @@ export default function DraftHandler(props: Props) {
|
|||
}
|
||||
|
||||
newUploadError(null);
|
||||
}, [intl, newUploadError, maxFileCount, maxFileSize, serverUrl, files?.length, channelId, rootId]);
|
||||
}, [intl, newUploadError, maxFileSize, serverUrl, files?.length, channelId, rootId]);
|
||||
|
||||
// This effect mainly handles keeping clean the uploadErrorHandlers, and
|
||||
// reinstantiate them on component mount and file retry.
|
||||
|
|
|
|||
|
|
@ -4,42 +4,23 @@
|
|||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {combineLatest, of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {DEFAULT_SERVER_MAX_FILE_SIZE} from '@constants/post_draft';
|
||||
import {observeConfig, observeLicense} from '@queries/servers/system';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
import {observeCanUploadFiles, observeConfigIntValue, observeMaxFileCount} from '@queries/servers/system';
|
||||
|
||||
import DraftHandler from './draft_handler';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
|
||||
const license = observeLicense(database);
|
||||
|
||||
const canUploadFiles = combineLatest([config, license]).pipe(
|
||||
switchMap(([c, l]) => of$(
|
||||
c?.EnableFileAttachments === 'true' ||
|
||||
(l?.IsLicensed !== 'true' && l?.Compliance !== 'true' && c?.EnableMobileFileUpload === 'true'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const maxFileSize = config.pipe(
|
||||
switchMap((cfg) => of$(parseInt(cfg?.MaxFileSize || '0', 10) || DEFAULT_SERVER_MAX_FILE_SIZE)),
|
||||
);
|
||||
|
||||
const maxFileCount = config.pipe(
|
||||
switchMap((cfg) => of$(isMinimumServerVersion(cfg?.Version || '', 6, 0) ? 10 : 5)),
|
||||
);
|
||||
const canUploadFiles = observeCanUploadFiles(database);
|
||||
const maxFileSize = observeConfigIntValue(database, 'MaxFileSize', DEFAULT_SERVER_MAX_FILE_SIZE);
|
||||
const maxFileCount = observeMaxFileCount(database);
|
||||
|
||||
return {
|
||||
maxFileSize,
|
||||
maxFileCount,
|
||||
canUploadFiles,
|
||||
maxFileCount,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {of as of$} from 'rxjs';
|
|||
import {switchMap, distinctUntilChanged} from 'rxjs/operators';
|
||||
|
||||
import {observeChannel} from '@queries/servers/channel';
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeConfigIntValue} from '@queries/servers/system';
|
||||
|
||||
import PostInput from './post_input';
|
||||
|
||||
|
|
@ -20,18 +20,9 @@ type OwnProps = {
|
|||
}
|
||||
|
||||
const enhanced = withObservables(['channelId'], ({database, channelId}: WithDatabaseArgs & OwnProps) => {
|
||||
const config = observeConfig(database);
|
||||
const timeBetweenUserTypingUpdatesMilliseconds = config.pipe(
|
||||
switchMap((cfg) => of$(parseInt(cfg?.TimeBetweenUserTypingUpdatesMilliseconds || '0', 10))),
|
||||
);
|
||||
|
||||
const enableUserTypingMessage = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.EnableUserTypingMessages === 'true')),
|
||||
);
|
||||
|
||||
const maxNotificationsPerChannel = config.pipe(
|
||||
switchMap((cfg) => of$(parseInt(cfg?.MaxNotificationsPerChannel || '0', 10))),
|
||||
);
|
||||
const timeBetweenUserTypingUpdatesMilliseconds = observeConfigIntValue(database, 'TimeBetweenUserTypingUpdatesMilliseconds');
|
||||
const enableUserTypingMessage = observeConfigBooleanValue(database, 'EnableUserTypingMessages');
|
||||
const maxNotificationsPerChannel = observeConfigIntValue(database, 'MaxNotificationsPerChannel');
|
||||
|
||||
const channel = observeChannel(database, channelId);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,31 +4,16 @@
|
|||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {combineLatest, of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig, observeLicense} from '@queries/servers/system';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
import {observeCanUploadFiles, observeMaxFileCount} from '@queries/servers/system';
|
||||
|
||||
import QuickActions from './quick_actions';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const license = observeLicense(database);
|
||||
|
||||
const canUploadFiles = combineLatest([config, license]).pipe(
|
||||
switchMap(([c, l]) => of$(
|
||||
c?.EnableFileAttachments === 'true' ||
|
||||
(l?.IsLicensed !== 'true' && l?.Compliance !== 'true' && c?.EnableMobileFileUpload === 'true'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const maxFileCount = config.pipe(
|
||||
switchMap((cfg) => of$(isMinimumServerVersion(cfg?.Version || '', 6, 0) ? 10 : 5)),
|
||||
);
|
||||
const canUploadFiles = observeCanUploadFiles(database);
|
||||
const maxFileCount = observeMaxFileCount(database);
|
||||
|
||||
return {
|
||||
canUploadFiles,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {MAX_MESSAGE_LENGTH_FALLBACK} from '@constants/post_draft';
|
|||
import {observeChannel, observeCurrentChannel} from '@queries/servers/channel';
|
||||
import {queryAllCustomEmojis} from '@queries/servers/custom_emoji';
|
||||
import {observePermissionForChannel} from '@queries/servers/role';
|
||||
import {observeConfig, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeConfigIntValue, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeUser} from '@queries/servers/user';
|
||||
|
||||
import SendHandler from './send_handler';
|
||||
|
|
@ -42,16 +42,9 @@ const enhanced = withObservables([], (ownProps: WithDatabaseArgs & OwnProps) =>
|
|||
switchMap((u) => of$(u?.status === General.OUT_OF_OFFICE)),
|
||||
);
|
||||
|
||||
const config = observeConfig(database);
|
||||
const enableConfirmNotificationsToChannel = config.pipe(
|
||||
switchMap((cfg) => of$(Boolean(cfg?.EnableConfirmNotificationsToChannel === 'true'))),
|
||||
);
|
||||
const isTimezoneEnabled = config.pipe(
|
||||
switchMap((cfg) => of$(Boolean(cfg?.ExperimentalTimezone === 'true'))),
|
||||
);
|
||||
const maxMessageLength = config.pipe(
|
||||
switchMap((cfg) => of$(parseInt(cfg?.MaxPostSize || '0', 10) || MAX_MESSAGE_LENGTH_FALLBACK)),
|
||||
);
|
||||
const enableConfirmNotificationsToChannel = observeConfigBooleanValue(database, 'EnableConfirmNotificationsToChannel');
|
||||
const isTimezoneEnabled = observeConfigBooleanValue(database, 'ExperimentalTimezone');
|
||||
const maxMessageLength = observeConfigIntValue(database, 'MaxPostSize', MAX_MESSAGE_LENGTH_FALLBACK);
|
||||
|
||||
const useChannelMentions = combineLatest([channel, currentUser]).pipe(
|
||||
switchMap(([c, u]) => {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {of as of$, combineLatest} from 'rxjs';
|
|||
import {Preferences} from '@constants';
|
||||
import {getPreferenceAsBool} from '@helpers/api/preference';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue} from '@queries/servers/system';
|
||||
|
||||
import Opengraph from './opengraph';
|
||||
|
||||
|
|
@ -21,12 +21,12 @@ const enhance = withObservables(
|
|||
return {showLinkPreviews: of$(false)};
|
||||
}
|
||||
|
||||
const config = observeConfig(database);
|
||||
const linkPreviewsConfig = observeConfigBooleanValue(database, 'EnableLinkPreviews');
|
||||
const linkPreviewPreference = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY).
|
||||
observeWithColumns(['value']);
|
||||
const showLinkPreviews = combineLatest([config, linkPreviewPreference], (cfg, pref) => {
|
||||
const showLinkPreviews = combineLatest([linkPreviewsConfig, linkPreviewPreference], (cfg, pref) => {
|
||||
const previewsEnabled = getPreferenceAsBool(pref, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, true);
|
||||
return of$(previewsEnabled && cfg?.EnableLinkPreviews === 'true');
|
||||
return of$(previewsEnabled && cfg);
|
||||
});
|
||||
|
||||
return {showLinkPreviews};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ type Props = {
|
|||
enableEmoji?: boolean;
|
||||
enableHardBreak?: boolean;
|
||||
enableSoftBreak?: boolean;
|
||||
textStyle: StyleProp<TextStyle>;
|
||||
textStyle?: StyleProp<TextStyle>;
|
||||
value: string;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import FormattedTime from '@components/formatted_time';
|
|||
import {Preferences} from '@constants';
|
||||
import {getPreferenceAsBool} from '@helpers/api/preference';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue} from '@queries/servers/system';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
|
@ -80,10 +80,9 @@ const SystemHeader = ({isMilitaryTime, isTimezoneEnabled, createAt, theme, user}
|
|||
};
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const preferences = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time').
|
||||
observeWithColumns(['value']);
|
||||
const isTimezoneEnabled = config.pipe(map((cfg) => cfg?.ExperimentalTimezone === 'true'));
|
||||
const isTimezoneEnabled = observeConfigBooleanValue(database, 'ExperimentalTimezone');
|
||||
const isMilitaryTime = preferences.pipe(
|
||||
map((prefs) => getPreferenceAsBool(prefs, Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', false)),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import React, {useMemo} from 'react';
|
|||
import {StyleProp, Text, TextStyle, useWindowDimensions, View, ViewStyle} from 'react-native';
|
||||
import Animated, {AnimatedStyleProp} from 'react-native-reanimated';
|
||||
|
||||
import {useIsTablet} from '@app/hooks/device';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,23 +3,16 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeCurrentUserId} from '@queries/servers/system';
|
||||
|
||||
import UserItem from './user_item';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const isCustomStatusEnabled = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.EnableCustomUserStatuses === 'true')),
|
||||
);
|
||||
const showFullName = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.ShowFullName === 'true')),
|
||||
);
|
||||
const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses');
|
||||
const showFullName = observeConfigBooleanValue(database, 'ShowFullName');
|
||||
const currentUserId = observeCurrentUserId(database);
|
||||
return {
|
||||
isCustomStatusEnabled,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const MM_TABLES = {
|
|||
CHANNEL: 'Channel',
|
||||
CHANNEL_INFO: 'ChannelInfo',
|
||||
CHANNEL_MEMBERSHIP: 'ChannelMembership',
|
||||
CONFIG: 'Config',
|
||||
CUSTOM_EMOJI: 'CustomEmoji',
|
||||
DRAFT: 'Draft',
|
||||
FILE: 'File',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {DatabaseType, MIGRATION_EVENTS, MM_TABLES} from '@constants/database';
|
|||
import AppDatabaseMigrations from '@database/migration/app';
|
||||
import ServerDatabaseMigrations from '@database/migration/server';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
import {CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
|
|
@ -47,7 +47,7 @@ class DatabaseManager {
|
|||
constructor() {
|
||||
this.appModels = [InfoModel, GlobalModel, ServersModel];
|
||||
this.serverModels = [
|
||||
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {DeviceEventEmitter, Platform} from 'react-native';
|
|||
import DeviceInfo from 'react-native-device-info';
|
||||
import FileSystem from 'react-native-fs';
|
||||
|
||||
import {DatabaseType, MIGRATION_EVENTS, MM_TABLES} from '@constants/database';
|
||||
import {DatabaseType, MIGRATION_EVENTS, MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import AppDatabaseMigrations from '@database/migration/app';
|
||||
import ServerDatabaseMigrations from '@database/migration/server';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
|
|
@ -16,13 +16,14 @@ import {CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, Cha
|
|||
GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, UserModel,
|
||||
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, UserModel, ConfigModel,
|
||||
} from '@database/models/server';
|
||||
import AppDataOperator from '@database/operator/app_data_operator';
|
||||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import {schema as appSchema} from '@database/schema/app';
|
||||
import {serverSchema} from '@database/schema/server';
|
||||
import {queryActiveServer, queryServer, queryServerByIdentifier} from '@queries/app/servers';
|
||||
import {querySystemValue} from '@queries/servers/system';
|
||||
import {deleteLegacyFileCache} from '@utils/file';
|
||||
import {emptyFunction} from '@utils/general';
|
||||
import {logDebug, logError} from '@utils/log';
|
||||
|
|
@ -45,7 +46,7 @@ class DatabaseManager {
|
|||
constructor() {
|
||||
this.appModels = [InfoModel, GlobalModel, ServersModel];
|
||||
this.serverModels = [
|
||||
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
|
|
@ -178,13 +179,38 @@ class DatabaseManager {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
private initServerDatabase = async (serverUrl: string): Promise<void> => {
|
||||
await this.createServerDatabase({
|
||||
const serverDatabase = await this.createServerDatabase({
|
||||
config: {
|
||||
dbName: serverUrl,
|
||||
dbType: DatabaseType.SERVER,
|
||||
serverUrl,
|
||||
},
|
||||
});
|
||||
|
||||
// Migration for config
|
||||
if (serverDatabase) {
|
||||
const {database, operator} = serverDatabase;
|
||||
const oldConfigList = await querySystemValue(database, SYSTEM_IDENTIFIERS.CONFIG).fetch();
|
||||
if (oldConfigList.length) {
|
||||
const oldConfigModel = oldConfigList[0];
|
||||
const oldConfig = oldConfigModel.value as ClientConfig;
|
||||
|
||||
const configs = [];
|
||||
let k: keyof ClientConfig;
|
||||
for (k in oldConfig) {
|
||||
// Check to silence eslint (guard-for-in)
|
||||
if (Object.prototype.hasOwnProperty.call(oldConfig, k)) {
|
||||
configs.push({
|
||||
id: k,
|
||||
value: oldConfig[k],
|
||||
});
|
||||
}
|
||||
}
|
||||
const models = await operator.handleConfigs({configs, configsToDelete: [], prepareRecordsOnly: true});
|
||||
|
||||
operator.batchRecords([...models, oldConfigModel.prepareDestroyPermanently()]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@
|
|||
// NOTE : To implement migration, please follow this document
|
||||
// https://nozbe.github.io/WatermelonDB/Advanced/Migrations.html
|
||||
|
||||
import {schemaMigrations, addColumns} from '@nozbe/watermelondb/Schema/migrations';
|
||||
import {schemaMigrations, addColumns, createTable} from '@nozbe/watermelondb/Schema/migrations';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {tableSchemaSpec as configSpec} from '@database/schema/server/table_schemas/config';
|
||||
|
||||
const {SERVER: {
|
||||
GROUP,
|
||||
|
|
@ -16,6 +17,12 @@ const {SERVER: {
|
|||
}} = MM_TABLES;
|
||||
|
||||
export default schemaMigrations({migrations: [
|
||||
{
|
||||
toVersion: 5,
|
||||
steps: [
|
||||
createTable(configSpec),
|
||||
],
|
||||
},
|
||||
{
|
||||
toVersion: 4,
|
||||
steps: [
|
||||
|
|
|
|||
23
app/database/models/server/config.ts
Normal file
23
app/database/models/server/config.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Model} from '@nozbe/watermelondb';
|
||||
import {field} from '@nozbe/watermelondb/decorators';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type ConfigModelInterface from '@typings/database/models/servers/config';
|
||||
|
||||
const {CONFIG} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
* The Config model is another set of key-value pair combination but this one
|
||||
* will hold the server configuration.
|
||||
*/
|
||||
export default class ConfigModel extends Model implements ConfigModelInterface {
|
||||
/** table (name) : Config */
|
||||
static table = CONFIG;
|
||||
|
||||
/** value : The value for that config/information and whose key will be the id column */
|
||||
@field('value') value!: string;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ export {default as CategoryChannelModel} from './category_channel';
|
|||
export {default as ChannelInfoModel} from './channel_info';
|
||||
export {default as ChannelMembershipModel} from './channel_membership';
|
||||
export {default as ChannelModel} from './channel';
|
||||
export {default as ConfigModel} from './config';
|
||||
export {default as CustomEmojiModel} from './custom_emoji';
|
||||
export {default as DraftModel} from './draft';
|
||||
export {default as FileModel} from './file';
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {
|
||||
transformConfigRecord,
|
||||
transformCustomEmojiRecord,
|
||||
transformRoleRecord,
|
||||
transformSystemRecord,
|
||||
|
|
@ -95,6 +96,30 @@ describe('*** DataOperator: Base Handlers tests ***', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('=> HandleConfig: should write to the CONFIG table', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
|
||||
|
||||
const configs = [{id: 'config-1', value: 'config-1'}];
|
||||
const configsToDelete = [{id: 'toDelete', value: 'toDelete'}];
|
||||
|
||||
await operator.handleConfigs({
|
||||
configs,
|
||||
configsToDelete,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledWith({
|
||||
fieldName: 'id',
|
||||
transformer: transformConfigRecord,
|
||||
createOrUpdateRawValues: configs,
|
||||
tableName: 'Config',
|
||||
prepareRecordsOnly: false,
|
||||
deleteRawValues: configsToDelete,
|
||||
});
|
||||
});
|
||||
|
||||
it('=> No table name: should not call execute if tableName is invalid', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import {MM_TABLES} from '@constants/database';
|
||||
import BaseDataOperator from '@database/operator/base_data_operator';
|
||||
import {
|
||||
transformConfigRecord,
|
||||
transformCustomEmojiRecord,
|
||||
transformRoleRecord,
|
||||
transformSystemRecord,
|
||||
|
|
@ -12,12 +13,12 @@ import {getUniqueRawsBy} from '@database/operator/utils/general';
|
|||
import {logWarning} from '@utils/log';
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
import type {HandleCustomEmojiArgs, HandleRoleArgs, HandleSystemArgs, OperationArgs} from '@typings/database/database';
|
||||
import type {HandleConfigArgs, HandleCustomEmojiArgs, HandleRoleArgs, HandleSystemArgs, OperationArgs} from '@typings/database/database';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type RoleModel from '@typings/database/models/servers/role';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
|
||||
const {SERVER: {CUSTOM_EMOJI, ROLE, SYSTEM}} = MM_TABLES;
|
||||
const {SERVER: {CONFIG, CUSTOM_EMOJI, ROLE, SYSTEM}} = MM_TABLES;
|
||||
|
||||
export default class ServerDataOperatorBase extends BaseDataOperator {
|
||||
handleRole = async ({roles, prepareRecordsOnly = true}: HandleRoleArgs) => {
|
||||
|
|
@ -71,6 +72,24 @@ export default class ServerDataOperatorBase extends BaseDataOperator {
|
|||
}) as Promise<SystemModel[]>;
|
||||
};
|
||||
|
||||
handleConfigs = async ({configs, configsToDelete, prepareRecordsOnly = true}: HandleConfigArgs) => {
|
||||
if (!configs?.length && !configsToDelete?.length) {
|
||||
logWarning(
|
||||
'An empty or undefined "configs" and "configsToDelete" arrays has been passed to the handleConfigs',
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'id',
|
||||
transformer: transformConfigRecord,
|
||||
prepareRecordsOnly,
|
||||
createOrUpdateRawValues: getUniqueRawsBy({raws: configs, key: 'id'}),
|
||||
tableName: CONFIG,
|
||||
deleteRawValues: configsToDelete,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* execute: Handles the Create/Update operations on an table.
|
||||
* @param {OperationArgs} execute
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {MM_TABLES, OperationType} from '@constants/database';
|
|||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import type ConfigModel from '@typings/database/models/servers/config';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type RoleModel from '@typings/database/models/servers/role';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
|
|
@ -13,6 +14,7 @@ const {
|
|||
CUSTOM_EMOJI,
|
||||
ROLE,
|
||||
SYSTEM,
|
||||
CONFIG,
|
||||
} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
|
|
@ -94,3 +96,28 @@ export const transformSystemRecord = ({action, database, value}: TransformerArgs
|
|||
fieldsMapper,
|
||||
}) as Promise<SystemModel>;
|
||||
};
|
||||
|
||||
/**
|
||||
* transformConfigRecord: Prepares a record of the SERVER database 'Config' table for update or create actions.
|
||||
* @param {TransformerArgs} operator
|
||||
* @param {Database} operator.database
|
||||
* @param {RecordPair} operator.value
|
||||
* @returns {Promise<ConfigModel>}
|
||||
*/
|
||||
export const transformConfigRecord = ({action, database, value}: TransformerArgs): Promise<ConfigModel> => {
|
||||
const raw = value.raw as IdValue;
|
||||
|
||||
// If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database
|
||||
const fieldsMapper = (config: ConfigModel) => {
|
||||
config._raw.id = raw?.id;
|
||||
config.value = raw?.value as string;
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: CONFIG,
|
||||
value,
|
||||
fieldsMapper,
|
||||
}) as Promise<ConfigModel>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
ChannelInfoSchema,
|
||||
ChannelMembershipSchema,
|
||||
ChannelSchema,
|
||||
ConfigSchema,
|
||||
CustomEmojiSchema,
|
||||
DraftSchema,
|
||||
FileSchema,
|
||||
|
|
@ -37,13 +38,14 @@ import {
|
|||
} from './table_schemas';
|
||||
|
||||
export const serverSchema: AppSchema = appSchema({
|
||||
version: 4,
|
||||
version: 5,
|
||||
tables: [
|
||||
CategorySchema,
|
||||
CategoryChannelSchema,
|
||||
ChannelInfoSchema,
|
||||
ChannelMembershipSchema,
|
||||
ChannelSchema,
|
||||
ConfigSchema,
|
||||
CustomEmojiSchema,
|
||||
DraftSchema,
|
||||
FileSchema,
|
||||
|
|
|
|||
19
app/database/schema/server/table_schemas/config.ts
Normal file
19
app/database/schema/server/table_schemas/config.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type {TableSchemaSpec} from '@nozbe/watermelondb/Schema';
|
||||
|
||||
const {CONFIG} = MM_TABLES.SERVER;
|
||||
|
||||
export const tableSchemaSpec: TableSchemaSpec = {
|
||||
name: CONFIG,
|
||||
columns: [
|
||||
{name: 'value', type: 'string'},
|
||||
],
|
||||
};
|
||||
|
||||
export default tableSchema(tableSchemaSpec);
|
||||
|
|
@ -31,3 +31,4 @@ export {default as ThreadSchema} from './thread';
|
|||
export {default as ThreadParticipantSchema} from './thread_participant';
|
||||
export {default as ThreadInTeamSchema} from './thread_in_team';
|
||||
export {default as UserSchema} from './user';
|
||||
export {default as ConfigSchema} from './config';
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const {
|
|||
CHANNEL,
|
||||
CHANNEL_INFO,
|
||||
CHANNEL_MEMBERSHIP,
|
||||
CONFIG,
|
||||
CUSTOM_EMOJI,
|
||||
DRAFT,
|
||||
FILE,
|
||||
|
|
@ -43,7 +44,8 @@ const {
|
|||
describe('*** Test schema for SERVER database ***', () => {
|
||||
it('=> The SERVER SCHEMA should strictly match', () => {
|
||||
expect(serverSchema).toEqual({
|
||||
version: 4,
|
||||
version: 5,
|
||||
unsafeSql: undefined,
|
||||
tables: {
|
||||
[CATEGORY]: {
|
||||
name: CATEGORY,
|
||||
|
|
@ -145,6 +147,16 @@ describe('*** Test schema for SERVER database ***', () => {
|
|||
{name: 'scheme_admin', type: 'boolean'},
|
||||
],
|
||||
},
|
||||
[CONFIG]: {
|
||||
name: CONFIG,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
value: {name: 'value', type: 'string'},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'value', type: 'string'},
|
||||
],
|
||||
},
|
||||
[CUSTOM_EMOJI]: {
|
||||
name: CUSTOM_EMOJI,
|
||||
unsafeSql: undefined,
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ export function getPreferenceAsInt(preferences: PreferenceType[] | PreferenceMod
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
export function getTeammateNameDisplaySetting(preferences: PreferenceType[] | PreferenceModel[], config?: ClientConfig, license?: ClientLicense) {
|
||||
const useAdminTeammateNameDisplaySetting = license?.LockTeammateNameDisplay === 'true' && config?.LockTeammateNameDisplay === 'true';
|
||||
export function getTeammateNameDisplaySetting(preferences: PreferenceType[] | PreferenceModel[], lockTeammateNameDisplay?: string, teammateNameDisplay?: string, license?: ClientLicense) {
|
||||
const useAdminTeammateNameDisplaySetting = license?.LockTeammateNameDisplay === 'true' && lockTeammateNameDisplay === 'true';
|
||||
const preference = getPreferenceValue(preferences, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT, '') as string;
|
||||
if (preference && !useAdminTeammateNameDisplaySetting) {
|
||||
return preference;
|
||||
} else if (config?.TeammateNameDisplay) {
|
||||
return config.TeammateNameDisplay;
|
||||
} else if (teammateNameDisplay) {
|
||||
return teammateNameDisplay;
|
||||
}
|
||||
|
||||
return General.TEAMMATE_NAME_DISPLAY.SHOW_USERNAME;
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import {AppState, AppStateStatus, DeviceEventEmitter, Platform} from 'react-nati
|
|||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session';
|
||||
import {resetMomentLocale} from '@app/i18n';
|
||||
import {Events, Launch} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {resetMomentLocale} from '@i18n';
|
||||
import {getAllServerCredentials, removeServerCredentials} from '@init/credentials';
|
||||
import {relaunchApp} from '@init/launch';
|
||||
import PushNotifications from '@init/push_notifications';
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
|||
import NetworkManager from '@managers/network_manager';
|
||||
import {getChannelById} from '@queries/servers/channel';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {getConfig, getLicense} from '@queries/servers/system';
|
||||
import {getCurrentUser, getUserById} from '@queries/servers/user';
|
||||
import {displayUsername, getUserIdFromChannelName, isSystemAdmin} from '@utils/user';
|
||||
|
||||
|
|
@ -346,9 +346,10 @@ export const getEndCallMessage = async (serverUrl: string, channelId: string, cu
|
|||
if (channel.type === General.DM_CHANNEL) {
|
||||
const otherID = getUserIdFromChannelName(currentUserId, channel.name);
|
||||
const otherUser = await getUserById(database, otherID);
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT).fetch();
|
||||
const displaySetting = getTeammateNameDisplaySetting(preferences, config, license);
|
||||
const displaySetting = getTeammateNameDisplaySetting(preferences, config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
msg = intl.formatMessage({
|
||||
id: 'mobile.calls_end_msg_dm',
|
||||
defaultMessage: 'Are you sure you want to end the call with {displayName}?',
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import {encode} from '@msgpack/msgpack/dist';
|
|||
|
||||
import Calls from '@constants/calls';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {logDebug, logError} from '@utils/log';
|
||||
import {getConfigValue} from '@queries/servers/system';
|
||||
import {logError, logDebug} from '@utils/log';
|
||||
|
||||
const wsMinReconnectRetryTimeMs = 1000; // 1 second
|
||||
const wsReconnectionTimeout = 30000; // 30 seconds
|
||||
|
|
@ -42,8 +42,8 @@ export class WebSocketClient extends EventEmitter {
|
|||
return;
|
||||
}
|
||||
|
||||
const system = await getCommonSystemValues(database);
|
||||
const connectionUrl = (system.config.WebsocketURL || this.serverUrl) + this.wsPath;
|
||||
const websocketURL = await getConfigValue(database, 'WebsocketURL');
|
||||
const connectionUrl = (websocketURL || this.serverUrl) + this.wsPath;
|
||||
|
||||
this.ws = new WebSocket(`${connectionUrl}?connection_id=${this.connID}&sequence_number=${this.serverSeqNo}`, [], {headers: {authorization: `Bearer ${this.authToken}`}});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
import {of as of$, Observable} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
import {of as of$, Observable, combineLatest} from 'rxjs';
|
||||
import {switchMap, distinctUntilChanged} from 'rxjs/operators';
|
||||
|
||||
import {Config, Preferences} from '@constants';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import type ConfigModel from '@typings/database/models/servers/config';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
|
||||
export type PrepareCommonSystemValuesArgs = {
|
||||
config?: ClientConfig;
|
||||
lastUnreadChannelId?: string;
|
||||
currentChannelId?: string;
|
||||
currentTeamId?: string;
|
||||
|
|
@ -22,7 +23,7 @@ export type PrepareCommonSystemValuesArgs = {
|
|||
teamHistory?: string;
|
||||
}
|
||||
|
||||
const {SERVER: {SYSTEM}} = MM_TABLES;
|
||||
const {SERVER: {SYSTEM, CONFIG}} = MM_TABLES;
|
||||
|
||||
export const getCurrentChannelId = async (serverDatabase: Database): Promise<string> => {
|
||||
try {
|
||||
|
|
@ -94,7 +95,6 @@ export const observePushVerificationStatus = (database: Database): Observable<st
|
|||
|
||||
export const getCommonSystemValues = async (serverDatabase: Database) => {
|
||||
const systemRecords = (await serverDatabase.collections.get<SystemModel>(SYSTEM).query().fetch());
|
||||
let config: ClientConfig = {} as ClientConfig;
|
||||
let license: ClientLicense = {} as ClientLicense;
|
||||
let currentChannelId = '';
|
||||
let currentTeamId = '';
|
||||
|
|
@ -102,9 +102,6 @@ export const getCommonSystemValues = async (serverDatabase: Database) => {
|
|||
let lastUnreadChannelId = '';
|
||||
systemRecords.forEach((systemRecord) => {
|
||||
switch (systemRecord.id) {
|
||||
case SYSTEM_IDENTIFIERS.CONFIG:
|
||||
config = systemRecord.value;
|
||||
break;
|
||||
case SYSTEM_IDENTIFIERS.CURRENT_CHANNEL_ID:
|
||||
currentChannelId = systemRecord.value;
|
||||
break;
|
||||
|
|
@ -128,51 +125,75 @@ export const getCommonSystemValues = async (serverDatabase: Database) => {
|
|||
currentTeamId,
|
||||
currentUserId,
|
||||
lastUnreadChannelId,
|
||||
config,
|
||||
license,
|
||||
};
|
||||
};
|
||||
|
||||
export const getConfig = async (serverDatabase: Database) => {
|
||||
try {
|
||||
const config = await serverDatabase.get<SystemModel>(SYSTEM).find(SYSTEM_IDENTIFIERS.CONFIG);
|
||||
return (config?.value || {}) as ClientConfig;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
const fromModelToClientConfig = (list: ConfigModel[]) => {
|
||||
const config: {[key: string]: any} = {};
|
||||
list.forEach((v) => {
|
||||
config[v.id] = v.value;
|
||||
});
|
||||
return config as ClientConfig;
|
||||
};
|
||||
|
||||
export const getConfig = async (database: Database) => {
|
||||
const configList = await database.get<ConfigModel>(CONFIG).query().fetch();
|
||||
return fromModelToClientConfig(configList);
|
||||
};
|
||||
|
||||
export const queryConfigValue = (database: Database, key: keyof ClientConfig) => {
|
||||
return database.get<ConfigModel>(CONFIG).query(Q.where('id', Q.eq(key)));
|
||||
};
|
||||
|
||||
export const getConfigValue = async (database: Database, key: keyof ClientConfig) => {
|
||||
const list = await queryConfigValue(database, key).fetch();
|
||||
return list.length ? list[0].value : undefined;
|
||||
};
|
||||
|
||||
export const observeConfig = (database: Database): Observable<ClientConfig | undefined> => {
|
||||
return querySystemValue(database, SYSTEM_IDENTIFIERS.CONFIG).observe().pipe(
|
||||
switchMap((result) => (result.length ? result[0].observe() : of$({value: undefined}))),
|
||||
switchMap((model) => of$(model.value)),
|
||||
return database.get<ConfigModel>(CONFIG).query().observeWithColumns(['value']).pipe(
|
||||
switchMap((result) => of$(fromModelToClientConfig(result))),
|
||||
);
|
||||
};
|
||||
|
||||
export const observeConfigValue = (database: Database, key: keyof ClientConfig) => {
|
||||
return observeConfig(database).pipe(
|
||||
switchMap((cfg) => of$(cfg?.[key])),
|
||||
return queryConfigValue(database, key).observeWithColumns(['value']).pipe(
|
||||
switchMap((result) => of$(result.length ? result[0].value : undefined)),
|
||||
);
|
||||
};
|
||||
|
||||
export const observeMaxFileCount = (database: Database) => {
|
||||
return observeConfigValue(database, 'Version').pipe(
|
||||
switchMap((v) => of$(isMinimumServerVersion(v || '', 6, 0) ? 10 : 5)),
|
||||
);
|
||||
};
|
||||
|
||||
export const observeIsCustomStatusExpirySupported = (database: Database) => {
|
||||
return observeConfigValue(database, 'Version').pipe(
|
||||
switchMap((v) => of$(isMinimumServerVersion(v || '', 5, 37))),
|
||||
);
|
||||
};
|
||||
|
||||
export const observeConfigBooleanValue = (database: Database, key: keyof ClientConfig) => {
|
||||
return observeConfig(database).pipe(
|
||||
switchMap((cfg) => of$(cfg?.[key] === 'true')),
|
||||
return observeConfigValue(database, key).pipe(
|
||||
switchMap((v) => of$(v === 'true')),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
};
|
||||
|
||||
export const observeConfigIntValue = (database: Database, key: keyof ClientConfig, defaultValue = 0) => {
|
||||
return observeConfig(database).pipe(
|
||||
switchMap((cfg) => of$((parseInt(cfg?.[key] || '0', 10) || defaultValue))),
|
||||
return observeConfigValue(database, key).pipe(
|
||||
switchMap((v) => of$((parseInt(v || '0', 10) || defaultValue))),
|
||||
);
|
||||
};
|
||||
|
||||
export const observeIsPostPriorityEnabled = (database: Database) => {
|
||||
const config = observeConfig(database);
|
||||
return config.pipe(
|
||||
switchMap(
|
||||
(cfg) => of$(cfg?.FeatureFlagPostPriority === Config.TRUE && cfg?.PostPriority === Config.TRUE),
|
||||
),
|
||||
const featureFlag = observeConfigValue(database, 'FeatureFlagPostPriority');
|
||||
const cfg = observeConfigValue(database, 'PostPriority');
|
||||
return combineLatest([featureFlag, cfg]).pipe(
|
||||
switchMap(([ff, c]) => of$(ff === Config.TRUE && c === Config.TRUE)),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -297,14 +318,8 @@ export const patchTeamHistory = (operator: ServerDataOperator, value: string[],
|
|||
export async function prepareCommonSystemValues(
|
||||
operator: ServerDataOperator, values: PrepareCommonSystemValuesArgs): Promise<SystemModel[]> {
|
||||
try {
|
||||
const {config, lastUnreadChannelId, currentChannelId, currentTeamId, currentUserId, license} = values;
|
||||
const {lastUnreadChannelId, currentChannelId, currentTeamId, currentUserId, license} = values;
|
||||
const systems: IdValue[] = [];
|
||||
if (config !== undefined) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.CONFIG,
|
||||
value: JSON.stringify(config),
|
||||
});
|
||||
}
|
||||
|
||||
if (license !== undefined) {
|
||||
systems.push({
|
||||
|
|
@ -431,3 +446,17 @@ export const getExpiredSession = async (database: Database) => {
|
|||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const observeCanUploadFiles = (database: Database) => {
|
||||
const enableFileAttachments = observeConfigBooleanValue(database, 'EnableFileAttachments');
|
||||
const enableMobileFileUpload = observeConfigBooleanValue(database, 'EnableMobileFileUpload');
|
||||
const license = observeLicense(database);
|
||||
|
||||
return combineLatest([enableFileAttachments, enableMobileFileUpload, license]).pipe(
|
||||
switchMap(([efa, emfu, l]) => of$(
|
||||
efa ||
|
||||
(l?.IsLicensed !== 'true' && l?.Compliance !== 'true' && emfu),
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {MM_TABLES} from '@constants/database';
|
|||
import {processIsCRTEnabled} from '@utils/thread';
|
||||
|
||||
import {queryPreferencesByCategoryAndName} from './preference';
|
||||
import {getConfig, observeConfig} from './system';
|
||||
import {getConfig, observeConfigValue} from './system';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import type Model from '@nozbe/watermelondb/Model';
|
||||
|
|
@ -22,7 +22,7 @@ const {SERVER: {CHANNEL, POST, THREAD, THREADS_IN_TEAM, THREAD_PARTICIPANT, USER
|
|||
export const getIsCRTEnabled = async (database: Database): Promise<boolean> => {
|
||||
const config = await getConfig(database);
|
||||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).fetch();
|
||||
return processIsCRTEnabled(preferences, config);
|
||||
return processIsCRTEnabled(preferences, config?.CollapsedThreads, config?.FeatureFlagCollapsedThreads);
|
||||
};
|
||||
|
||||
export const getThreadById = async (database: Database, threadId: string) => {
|
||||
|
|
@ -35,11 +35,12 @@ export const getThreadById = async (database: Database, threadId: string) => {
|
|||
};
|
||||
|
||||
export const observeIsCRTEnabled = (database: Database) => {
|
||||
const config = observeConfig(database);
|
||||
const cfgValue = observeConfigValue(database, 'CollapsedThreads');
|
||||
const featureFlag = observeConfigValue(database, 'FeatureFlagCollapsedThreads');
|
||||
const preferences = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).observeWithColumns(['value']);
|
||||
return combineLatest([config, preferences]).pipe(
|
||||
return combineLatest([cfgValue, featureFlag, preferences]).pipe(
|
||||
map(
|
||||
([cfg, prefs]) => processIsCRTEnabled(prefs, cfg),
|
||||
([cfgV, ff, prefs]) => processIsCRTEnabled(prefs, cfgV, ff),
|
||||
),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {observeMyChannel} from '@queries/servers/channel';
|
|||
import {isChannelAdmin} from '@utils/user';
|
||||
|
||||
import {queryPreferencesByCategoryAndName} from './preference';
|
||||
import {observeConfig, observeCurrentUserId, observeLicense, getCurrentUserId, getConfig, getLicense} from './system';
|
||||
import {observeCurrentUserId, observeLicense, getCurrentUserId, getConfig, getLicense, observeConfigValue} from './system';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
|
|
@ -67,13 +67,14 @@ export async function prepareUsers(operator: ServerDataOperator, users: UserProf
|
|||
}
|
||||
|
||||
export const observeTeammateNameDisplay = (database: Database) => {
|
||||
const config = observeConfig(database);
|
||||
const lockTeammateNameDisplay = observeConfigValue(database, 'LockTeammateNameDisplay');
|
||||
const teammateNameDisplay = observeConfigValue(database, 'TeammateNameDisplay');
|
||||
const license = observeLicense(database);
|
||||
const preferences = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).
|
||||
observeWithColumns(['value']);
|
||||
return combineLatest([config, license, preferences]).pipe(
|
||||
return combineLatest([lockTeammateNameDisplay, teammateNameDisplay, license, preferences]).pipe(
|
||||
switchMap(
|
||||
([cfg, lcs, prefs]) => of$(getTeammateNameDisplaySetting(prefs, cfg, lcs)),
|
||||
([ltnd, tnd, lcs, prefs]) => of$(getTeammateNameDisplaySetting(prefs, ltnd, tnd, lcs)),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
|
@ -82,7 +83,7 @@ export async function getTeammateNameDisplay(database: Database) {
|
|||
const config = await getConfig(database);
|
||||
const license = await getLicense(database);
|
||||
const preferences = await queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).fetch();
|
||||
return getTeammateNameDisplaySetting(preferences, config, license);
|
||||
return getTeammateNameDisplaySetting(preferences, config?.LockTeammateNameDisplay, config?.TeammateNameDisplay, license);
|
||||
}
|
||||
|
||||
export const queryUsersLike = (database: Database, likeUsername: string) => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {switchMap} from 'rxjs/operators';
|
|||
import {Permissions} from '@constants';
|
||||
import {queryAllMyChannel} from '@queries/servers/channel';
|
||||
import {queryRolesByNames} from '@queries/servers/role';
|
||||
import {observeConfig, observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeUser} from '@queries/servers/user';
|
||||
import {hasPermission} from '@utils/role';
|
||||
|
||||
|
|
@ -18,15 +18,8 @@ import SearchHandler from './search_handler';
|
|||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
|
||||
const sharedChannelsEnabled = config.pipe(
|
||||
switchMap((v) => of$(v?.ExperimentalSharedChannels === 'true')),
|
||||
);
|
||||
|
||||
const canShowArchivedChannels = config.pipe(
|
||||
switchMap((v) => of$(v?.ExperimentalViewArchivedChannels === 'true')),
|
||||
);
|
||||
const sharedChannelsEnabled = observeConfigBooleanValue(database, 'ExperimentalSharedChannels');
|
||||
const canShowArchivedChannels = observeConfigBooleanValue(database, 'ExperimentalViewArchivedChannels');
|
||||
|
||||
const currentTeamId = observeCurrentTeamId(database);
|
||||
const currentUserId = observeCurrentUserId(database);
|
||||
|
|
|
|||
|
|
@ -6,11 +6,7 @@ import withObservables from '@nozbe/with-observables';
|
|||
import {combineLatest, of as of$} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
|
||||
import {Preferences} from '@constants';
|
||||
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeConfig, observeLicense} from '@queries/servers/system';
|
||||
import {observeCurrentUser, observeUser} from '@queries/servers/user';
|
||||
import {observeCurrentUser, observeTeammateNameDisplay, observeUser} from '@queries/servers/user';
|
||||
import {displayUsername} from '@utils/user';
|
||||
|
||||
import PublicOrPrivateChannel from './public_or_private_channel';
|
||||
|
|
@ -21,16 +17,10 @@ import type ChannelModel from '@typings/database/models/servers/channel';
|
|||
const enhanced = withObservables([], ({channel, database}: {channel: ChannelModel} & WithDatabaseArgs) => {
|
||||
let creator;
|
||||
if (channel.creatorId) {
|
||||
const config = observeConfig(database);
|
||||
const license = observeLicense(database);
|
||||
const preferences = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).
|
||||
observeWithColumns(['value']);
|
||||
const me = observeCurrentUser(database);
|
||||
const profile = observeUser(database, channel.creatorId);
|
||||
|
||||
const teammateNameDisplay = combineLatest([preferences, config, license]).pipe(
|
||||
map(([prefs, cfg, lcs]) => getTeammateNameDisplaySetting(prefs, cfg, lcs)),
|
||||
);
|
||||
const teammateNameDisplay = observeTeammateNameDisplay(database);
|
||||
|
||||
creator = combineLatest([profile, teammateNameDisplay, me]).pipe(
|
||||
map(([user, displaySetting, currentUser]) => (user ? displayUsername(user, currentUser?.locale, displaySetting, true) : '')),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {switchMap} from 'rxjs/operators';
|
|||
|
||||
import {General} from '@constants';
|
||||
import {observeProfileLongPresTutorial} from '@queries/app/global';
|
||||
import {observeConfig, observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeConfigValue, observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeTeammateNameDisplay} from '@queries/servers/user';
|
||||
|
||||
import CreateDirectMessage from './create_direct_message';
|
||||
|
|
@ -16,8 +16,8 @@ import CreateDirectMessage from './create_direct_message';
|
|||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const restrictDirectMessage = observeConfig(database).pipe(
|
||||
switchMap((cfg) => of$(cfg?.RestrictDirectMessage !== General.RESTRICT_DIRECT_MESSAGE_ANY)),
|
||||
const restrictDirectMessage = observeConfigValue(database, 'RestrictDirectMessage').pipe(
|
||||
switchMap((v) => of$(v !== General.RESTRICT_DIRECT_MESSAGE_ANY)),
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
|
||||
import {observeIsCustomStatusExpirySupported} from '@queries/servers/system';
|
||||
|
||||
import CustomStatusSuggestion from './custom_status_suggestion';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
return {
|
||||
isExpirySupported: observeIsCustomStatusExpirySupported(database),
|
||||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(CustomStatusSuggestion));
|
||||
|
|
@ -13,7 +13,6 @@ import CustomStatusSuggestion from './custom_status_suggestion';
|
|||
|
||||
type Props = {
|
||||
intl: IntlShape;
|
||||
isExpirySupported: boolean;
|
||||
onHandleCustomStatusSuggestionClick: (status: UserCustomStatus) => void;
|
||||
recentCustomStatuses: UserCustomStatus[];
|
||||
theme: Theme;
|
||||
|
|
@ -57,7 +56,6 @@ const defaultCustomStatusSuggestions: DefaultUserCustomStatus[] = [
|
|||
|
||||
const CustomStatusSuggestions = ({
|
||||
intl,
|
||||
isExpirySupported,
|
||||
onHandleCustomStatusSuggestionClick,
|
||||
recentCustomStatuses,
|
||||
theme,
|
||||
|
|
@ -81,7 +79,6 @@ const CustomStatusSuggestions = ({
|
|||
theme={theme}
|
||||
separator={index !== arr.length - 1}
|
||||
duration={status.duration}
|
||||
isExpirySupported={isExpirySupported}
|
||||
/>
|
||||
));
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import CustomStatusSuggestion from '@screens/custom_status/components/custom_sta
|
|||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
isExpirySupported: boolean;
|
||||
onHandleClear: (status: UserCustomStatus) => void;
|
||||
onHandleSuggestionClick: (status: UserCustomStatus) => void;
|
||||
recentCustomStatuses: UserCustomStatus[];
|
||||
|
|
@ -38,7 +37,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const RecentCustomStatuses = ({isExpirySupported, onHandleClear, onHandleSuggestionClick, recentCustomStatuses, theme}: Props) => {
|
||||
const RecentCustomStatuses = ({onHandleClear, onHandleSuggestionClick, recentCustomStatuses, theme}: Props) => {
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
if (recentCustomStatuses.length === 0) {
|
||||
|
|
@ -66,7 +65,6 @@ const RecentCustomStatuses = ({isExpirySupported, onHandleClear, onHandleSuggest
|
|||
separator={index !== recentCustomStatuses.length - 1}
|
||||
duration={status.duration}
|
||||
expires_at={status.expires_at}
|
||||
isExpirySupported={isExpirySupported}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ import {injectIntl, IntlShape} from 'react-intl';
|
|||
import {BackHandler, DeviceEventEmitter, Keyboard, KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native';
|
||||
import {EventSubscription, Navigation, NavigationButtonPressedEvent, NavigationComponent, NavigationComponentProps} from 'react-native-navigation';
|
||||
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {updateLocalCustomStatus} from '@actions/local/user';
|
||||
import {removeRecentCustomStatus, updateCustomStatus, unsetCustomStatus} from '@actions/remote/user';
|
||||
|
|
@ -20,11 +18,11 @@ import {Events, Screens} from '@constants';
|
|||
import {CustomStatusDurationEnum, SET_CUSTOM_STATUS_FAILURE} from '@constants/custom_status';
|
||||
import {withServerUrl} from '@context/server';
|
||||
import {withTheme} from '@context/theme';
|
||||
import {observeConfig, observeRecentCustomStatus} from '@queries/servers/system';
|
||||
import {observeIsCustomStatusExpirySupported, observeRecentCustomStatus} from '@queries/servers/system';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {dismissModal, goToScreen, showModal} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {getCurrentMomentForTimezone, getRoundedTime, isCustomStatusExpirySupported} from '@utils/helpers';
|
||||
import {getCurrentMomentForTimezone, getRoundedTime} from '@utils/helpers';
|
||||
import {logDebug} from '@utils/log';
|
||||
import {mergeNavigationOptions} from '@utils/navigation';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
|
@ -376,7 +374,6 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
|
|||
</View>
|
||||
{recentCustomStatuses.length > 0 && (
|
||||
<RecentCustomStatuses
|
||||
isExpirySupported={customStatusExpirySupported}
|
||||
onHandleClear={this.handleRecentCustomStatusClear}
|
||||
onHandleSuggestionClick={this.handleRecentCustomStatusSuggestionClick}
|
||||
recentCustomStatuses={recentCustomStatuses}
|
||||
|
|
@ -386,7 +383,6 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
|
|||
}
|
||||
<CustomStatusSuggestions
|
||||
intl={intl}
|
||||
isExpirySupported={customStatusExpirySupported}
|
||||
onHandleCustomStatusSuggestionClick={this.handleCustomStatusSuggestionClick}
|
||||
recentCustomStatuses={recentCustomStatuses}
|
||||
theme={theme}
|
||||
|
|
@ -404,13 +400,10 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
|
|||
const augmentCSM = injectIntl(withTheme(withServerUrl(CustomStatusModal)));
|
||||
|
||||
const enhancedCSM = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
return {
|
||||
currentUser: observeCurrentUser(database),
|
||||
customStatusExpirySupported: config.pipe(
|
||||
switchMap((cfg) => of$(isCustomStatusExpirySupported(cfg?.Version || ''))),
|
||||
),
|
||||
recentCustomStatuses: observeRecentCustomStatus(database),
|
||||
customStatusExpirySupported: observeIsCustomStatusExpirySupported(database),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {of as of$, combineLatest} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue} from '@queries/servers/system';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
|
||||
import EditProfile from './edit_profile';
|
||||
|
|
@ -14,35 +14,31 @@ import EditProfile from './edit_profile';
|
|||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const ldapFirstNameAttributeSet = observeConfigBooleanValue(database, 'LdapFirstNameAttributeSet');
|
||||
const ldapLastNameAttributeSet = observeConfigBooleanValue(database, 'LdapLastNameAttributeSet');
|
||||
const ldapNicknameAttributeSet = observeConfigBooleanValue(database, 'LdapNicknameAttributeSet');
|
||||
const ldapPositionAttributeSet = observeConfigBooleanValue(database, 'LdapPositionAttributeSet');
|
||||
|
||||
const samlFirstNameAttributeSet = observeConfigBooleanValue(database, 'SamlFirstNameAttributeSet');
|
||||
const samlLastNameAttributeSet = observeConfigBooleanValue(database, 'SamlLastNameAttributeSet');
|
||||
const samlNicknameAttributeSet = observeConfigBooleanValue(database, 'SamlNicknameAttributeSet');
|
||||
const samlPositionAttributeSet = observeConfigBooleanValue(database, 'SamlPositionAttributeSet');
|
||||
|
||||
return {
|
||||
currentUser: observeCurrentUser(database),
|
||||
lockedFirstName: config.pipe(
|
||||
switchMap(
|
||||
(cfg) => of$(cfg?.LdapFirstNameAttributeSet === 'true' || cfg?.SamlFirstNameAttributeSet === 'true'),
|
||||
),
|
||||
lockedFirstName: combineLatest([ldapFirstNameAttributeSet, samlFirstNameAttributeSet]).pipe(
|
||||
switchMap(([ldap, saml]) => of$(ldap || saml)),
|
||||
),
|
||||
lockedLastName: config.pipe(
|
||||
switchMap(
|
||||
(cfg) => of$(cfg?.LdapLastNameAttributeSet === 'true' || cfg?.SamlLastNameAttributeSet === 'true'),
|
||||
),
|
||||
lockedLastName: combineLatest([ldapLastNameAttributeSet, samlLastNameAttributeSet]).pipe(
|
||||
switchMap(([ldap, saml]) => of$(ldap || saml)),
|
||||
),
|
||||
lockedNickname: config.pipe(
|
||||
switchMap(
|
||||
(cfg) => of$(cfg?.LdapNicknameAttributeSet === 'true' || cfg?.SamlNicknameAttributeSet === 'true'),
|
||||
),
|
||||
lockedNickname: combineLatest([ldapNicknameAttributeSet, samlNicknameAttributeSet]).pipe(
|
||||
switchMap(([ldap, saml]) => of$(ldap || saml)),
|
||||
),
|
||||
lockedPosition: config.pipe(
|
||||
switchMap(
|
||||
(cfg) => of$(cfg?.LdapPositionAttributeSet === 'true' || cfg?.SamlPositionAttributeSet === 'true'),
|
||||
),
|
||||
),
|
||||
lockedPicture: config.pipe(
|
||||
switchMap(
|
||||
(cfg) => of$(cfg?.LdapPictureAttributeSet === 'true'),
|
||||
),
|
||||
lockedPosition: combineLatest([ldapPositionAttributeSet, samlPositionAttributeSet]).pipe(
|
||||
switchMap(([ldap, saml]) => of$(ldap || saml)),
|
||||
),
|
||||
lockedPicture: observeConfigBooleanValue(database, 'LdapPictureAttributeSet'),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {combineLatestWith, switchMap} from 'rxjs/operators';
|
|||
|
||||
import {General} from '@constants';
|
||||
import {observeArchiveChannelsByTerm, observeDirectChannelsByTerm, observeJoinedChannelsByTerm, observeNotDirectChannelsByTerm} from '@queries/servers/channel';
|
||||
import {observeConfig, observeCurrentTeamId} from '@queries/servers/system';
|
||||
import {observeConfigValue, observeCurrentTeamId} from '@queries/servers/system';
|
||||
import {queryJoinedTeams} from '@queries/servers/team';
|
||||
import {observeTeammateNameDisplay} from '@queries/servers/user';
|
||||
import {retrieveChannels} from '@screens/find_channels/utils';
|
||||
|
|
@ -50,8 +50,8 @@ const enhanced = withObservables(['term'], ({database, term}: EnhanceProps) => {
|
|||
const usersMatchStart = observeNotDirectChannelsByTerm(database, term, MAX_RESULTS, true);
|
||||
const usersMatch = observeNotDirectChannelsByTerm(database, term, MAX_RESULTS);
|
||||
|
||||
const restrictDirectMessage = observeConfig(database).pipe(
|
||||
switchMap((cfg) => of$(cfg?.RestrictDirectMessage !== General.RESTRICT_DIRECT_MESSAGE_ANY)),
|
||||
const restrictDirectMessage = observeConfigValue(database, 'RestrictDirectMessage').pipe(
|
||||
switchMap((v) => of$(v !== General.RESTRICT_DIRECT_MESSAGE_ANY)),
|
||||
);
|
||||
|
||||
const teammateDisplayNameSetting = observeTeammateNameDisplay(database);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {switchMap} from 'rxjs/operators';
|
|||
import {General} from '@constants';
|
||||
import {observeChannel} from '@queries/servers/channel';
|
||||
import {observePost} from '@queries/servers/post';
|
||||
import {observeConfig, observeCurrentChannelId, observeCurrentUserId, observeLicense} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeCurrentChannelId, observeCurrentUserId, observeLicense} from '@queries/servers/system';
|
||||
import {observeTeammateNameDisplay, observeUser} from '@queries/servers/user';
|
||||
|
||||
import Footer from './footer';
|
||||
|
|
@ -27,7 +27,6 @@ const enhanced = withObservables(['item'], ({database, item}: FooterProps) => {
|
|||
const currentChannelId = observeCurrentChannelId(database);
|
||||
const currentUserId = observeCurrentUserId(database);
|
||||
|
||||
const config = observeConfig(database);
|
||||
const license = observeLicense(database);
|
||||
const teammateNameDisplay = observeTeammateNameDisplay(database);
|
||||
|
||||
|
|
@ -47,10 +46,10 @@ const enhanced = withObservables(['item'], ({database, item}: FooterProps) => {
|
|||
return p?.channel.observe() || observeChannel(database, cId);
|
||||
}),
|
||||
);
|
||||
const enablePostUsernameOverride = config.pipe(switchMap((c) => of$(c?.EnablePostUsernameOverride === 'true')));
|
||||
const enablePostIconOverride = config.pipe(switchMap((c) => of$(c?.EnablePostIconOverride === 'true')));
|
||||
const enablePublicLink = config.pipe(switchMap((c) => of$(c?.EnablePublicLink === 'true')));
|
||||
const enableMobileFileDownload = config.pipe(switchMap((c) => of$(c?.EnableMobileFileDownload !== 'false')));
|
||||
const enablePostUsernameOverride = observeConfigBooleanValue(database, 'EnablePostUsernameOverride');
|
||||
const enablePostIconOverride = observeConfigBooleanValue(database, 'EnablePostIconOverride');
|
||||
const enablePublicLink = observeConfigBooleanValue(database, 'EnablePublicLink');
|
||||
const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload');
|
||||
const complianceDisabled = license.pipe(switchMap((l) => of$(l?.IsLicensed === 'false' || l?.Compliance === 'false')));
|
||||
const canDownloadFiles = combineLatest([enableMobileFileDownload, complianceDisabled]).pipe(
|
||||
switchMap(([download, compliance]) => of$(compliance || download)),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import type UserModel from '@typings/database/models/servers/user';
|
|||
|
||||
type AccountScreenProps = {
|
||||
currentUser: UserModel;
|
||||
customStatusExpirySupported: boolean;
|
||||
enableCustomUserStatuses: boolean;
|
||||
showFullName: boolean;
|
||||
};
|
||||
|
|
@ -57,7 +56,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const AccountScreen = ({currentUser, enableCustomUserStatuses, customStatusExpirySupported, showFullName}: AccountScreenProps) => {
|
||||
const AccountScreen = ({currentUser, enableCustomUserStatuses, showFullName}: AccountScreenProps) => {
|
||||
const theme = useTheme();
|
||||
const [start, setStart] = useState(false);
|
||||
const route = useRoute();
|
||||
|
|
@ -119,7 +118,6 @@ const AccountScreen = ({currentUser, enableCustomUserStatuses, customStatusExpir
|
|||
/>
|
||||
<AccountOptions
|
||||
enableCustomUserStatuses={enableCustomUserStatuses}
|
||||
isCustomStatusExpirySupported={customStatusExpirySupported}
|
||||
isTablet={isTablet}
|
||||
user={currentUser}
|
||||
theme={theme}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
|
||||
import {observeIsCustomStatusExpirySupported} from '@queries/servers/system';
|
||||
|
||||
import CustomLabel from './custom_label';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
return {
|
||||
isCustomStatusExpirySupported: observeIsCustomStatusExpirySupported(database),
|
||||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(CustomLabel));
|
||||
|
|
@ -38,12 +38,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
});
|
||||
|
||||
type CustomStatusProps = {
|
||||
isCustomStatusExpirySupported: boolean;
|
||||
isTablet: boolean;
|
||||
currentUser: UserModel;
|
||||
}
|
||||
|
||||
const CustomStatus = ({isCustomStatusExpirySupported, isTablet, currentUser}: CustomStatusProps) => {
|
||||
const CustomStatus = ({isTablet, currentUser}: CustomStatusProps) => {
|
||||
const theme = useTheme();
|
||||
const intl = useIntl();
|
||||
const serverUrl = useServerUrl();
|
||||
|
|
@ -96,7 +95,6 @@ const CustomStatus = ({isCustomStatusExpirySupported, isTablet, currentUser}: Cu
|
|||
/>
|
||||
<CustomLabel
|
||||
customStatus={customStatus!}
|
||||
isCustomStatusExpirySupported={isCustomStatusExpirySupported}
|
||||
isStatusSet={Boolean(isStatusSet)}
|
||||
onClearCustomStatus={clearCustomStatus}
|
||||
showRetryMessage={showRetryMessage}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import type UserModel from '@typings/database/models/servers/user';
|
|||
type AccountScreenProps = {
|
||||
user: UserModel;
|
||||
enableCustomUserStatuses: boolean;
|
||||
isCustomStatusExpirySupported: boolean;
|
||||
isTablet: boolean;
|
||||
theme: Theme;
|
||||
};
|
||||
|
|
@ -48,7 +47,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const AccountOptions = ({user, enableCustomUserStatuses, isCustomStatusExpirySupported, isTablet, theme}: AccountScreenProps) => {
|
||||
const AccountOptions = ({user, enableCustomUserStatuses, isTablet, theme}: AccountScreenProps) => {
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
|
|
@ -59,7 +58,6 @@ const AccountOptions = ({user, enableCustomUserStatuses, isCustomStatusExpirySup
|
|||
/>
|
||||
{enableCustomUserStatuses &&
|
||||
<CustomStatus
|
||||
isCustomStatusExpirySupported={isCustomStatusExpirySupported}
|
||||
isTablet={isTablet}
|
||||
currentUser={user}
|
||||
/>}
|
||||
|
|
|
|||
|
|
@ -4,35 +4,28 @@
|
|||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
import {combineLatestWith, switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeConfigValue} from '@queries/servers/system';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {isCustomStatusExpirySupported, isMinimumServerVersion} from '@utils/helpers';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
|
||||
import AccountScreen from './account';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const config = observeConfig(database);
|
||||
const showFullName = config.pipe((switchMap((cfg) => of$(cfg?.ShowFullName === 'true'))));
|
||||
const enableCustomUserStatuses = config.pipe((switchMap((cfg) => {
|
||||
return of$(cfg?.EnableCustomUserStatuses === 'true' && isMinimumServerVersion(cfg?.Version || '', 5, 36));
|
||||
})));
|
||||
const version = config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.Version || '')),
|
||||
);
|
||||
const customStatusExpirySupported = config.pipe(
|
||||
switchMap((cfg) => of$(isCustomStatusExpirySupported(cfg?.Version || ''))),
|
||||
const showFullName = observeConfigBooleanValue(database, 'ShowFullName');
|
||||
const version = observeConfigValue(database, 'Version');
|
||||
const enableCustomUserStatuses = observeConfigBooleanValue(database, 'EnableCustomUserStatuses').pipe(
|
||||
combineLatestWith(version),
|
||||
switchMap(([cfg, v]) => of$(cfg && isMinimumServerVersion(v || '', 5, 36))),
|
||||
);
|
||||
|
||||
return {
|
||||
currentUser: observeCurrentUser(database),
|
||||
enableCustomUserStatuses,
|
||||
customStatusExpirySupported,
|
||||
showFullName,
|
||||
version,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import withObservables from '@nozbe/with-observables';
|
|||
import {combineLatest, of as of$} from 'rxjs';
|
||||
import {map, switchMap, combineLatestWith} from 'rxjs/operators';
|
||||
|
||||
import {MyChannelModel} from '@app/database/models/server';
|
||||
import {General, Preferences} from '@constants';
|
||||
import {DMS_CATEGORY} from '@constants/categories';
|
||||
import {MyChannelModel} from '@database/models/server';
|
||||
import {getPreferenceAsBool} from '@helpers/api/preference';
|
||||
import {observeChannelsByCategoryChannelSortOrder, observeChannelsByLastPostAtInCategory} from '@queries/servers/categories';
|
||||
import {observeNotifyPropsByChannels, queryChannelsByNames, queryEmptyDirectAndGroupChannels} from '@queries/servers/channel';
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import withObservables from '@nozbe/with-observables';
|
|||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import Preferences from '@app/constants/preferences';
|
||||
import {PreferenceModel} from '@app/database/models/server';
|
||||
import {queryPreferencesByCategoryAndName} from '@app/queries/servers/preference';
|
||||
import Preferences from '@constants/preferences';
|
||||
import {PreferenceModel} from '@database/models/server';
|
||||
import {getPreferenceAsBool} from '@helpers/api/preference';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeCurrentChannelId, observeCurrentTeamId, observeOnlyUnreads} from '@queries/servers/system';
|
||||
import {observeUnreadsAndMentionsInTeam} from '@queries/servers/thread';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import React, {useCallback, useMemo, useState} from 'react';
|
|||
import {FlatList, ListRenderItemInfo, StyleProp, ViewStyle} from 'react-native';
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
|
||||
import {useIsTablet} from '@app/hooks/device';
|
||||
import {useImageAttachments} from '@app/hooks/files';
|
||||
import NoResultsWithTerm from '@components/no_results_with_term';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import {useImageAttachments} from '@hooks/files';
|
||||
import {GalleryAction} from '@typings/screens/gallery';
|
||||
import {
|
||||
getChannelNamesWithID,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import React, {useMemo} from 'react';
|
|||
import {ScaledSize, StyleSheet, useWindowDimensions, View} from 'react-native';
|
||||
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
|
||||
|
||||
import Loading from '@app/components/loading';
|
||||
import Loading from '@components/loading';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {TabTypes, TabType} from '@utils/search';
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-cont
|
|||
import {getPosts} from '@actions/local/post';
|
||||
import {addSearchToTeamSearchHistory} from '@actions/local/team';
|
||||
import {searchPosts, searchFiles} from '@actions/remote/search';
|
||||
import useDidUpdate from '@app/hooks/did_update';
|
||||
import Autocomplete from '@components/autocomplete';
|
||||
import FreezeScreen from '@components/freeze_screen';
|
||||
import Loading from '@components/loading';
|
||||
|
|
@ -22,6 +21,7 @@ import {BOTTOM_TAB_HEIGHT} from '@constants/view';
|
|||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useKeyboardHeight} from '@hooks/device';
|
||||
import useDidUpdate from '@hooks/did_update';
|
||||
import {useCollapsibleHeader} from '@hooks/header';
|
||||
import {FileFilter, FileFilters, filterFileExtensions} from '@utils/file';
|
||||
import {TabTypes, TabType} from '@utils/search';
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ import withObservables from '@nozbe/with-observables';
|
|||
import React from 'react';
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
import FastImage, {Source} from 'react-native-fast-image';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import NetworkManager from '@managers/network_manager';
|
||||
import {observeConfig} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue} from '@queries/servers/system';
|
||||
import {observeUser} from '@queries/servers/user';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
|
|
@ -89,14 +87,11 @@ const NotificationIcon = ({author, enablePostIconOverride, fromWebhook, override
|
|||
};
|
||||
|
||||
const enhanced = withObservables([], ({database, senderId}: WithDatabaseArgs & {senderId: string}) => {
|
||||
const config = observeConfig(database);
|
||||
const author = observeUser(database, senderId);
|
||||
|
||||
return {
|
||||
author,
|
||||
enablePostIconOverride: config.pipe(
|
||||
switchMap((cfg) => of$(cfg?.EnablePostIconOverride === 'true')),
|
||||
),
|
||||
enablePostIconOverride: observeConfigBooleanValue(database, 'EnablePostIconOverride'),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {General, Permissions, Post, Screens} from '@constants';
|
|||
import {MAX_ALLOWED_REACTIONS} from '@constants/emoji';
|
||||
import {observePost, observePostSaved} from '@queries/servers/post';
|
||||
import {observePermissionForChannel, observePermissionForPost} from '@queries/servers/role';
|
||||
import {observeConfig, observeLicense} from '@queries/servers/system';
|
||||
import {observeConfigBooleanValue, observeConfigIntValue, observeConfigValue, observeLicense} from '@queries/servers/system';
|
||||
import {observeIsCRTEnabled, observeThreadById} from '@queries/servers/thread';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
|
|
@ -73,11 +73,10 @@ const enhanced = withObservables([], ({combinedPost, post, showAddReaction, loca
|
|||
const channel = post.channel.observe();
|
||||
const channelIsArchived = channel.pipe(switchMap((ch: ChannelModel) => of$(ch.deleteAt !== 0)));
|
||||
const currentUser = observeCurrentUser(database);
|
||||
const config = observeConfig(database);
|
||||
const isLicensed = observeLicense(database).pipe(switchMap((lcs) => of$(lcs?.IsLicensed === 'true')));
|
||||
const allowEditPost = config.pipe(switchMap((cfg) => of$(cfg?.AllowEditPost)));
|
||||
const serverVersion = config.pipe(switchMap((cfg) => of$(cfg?.Version || '')));
|
||||
const postEditTimeLimit = config.pipe(switchMap((cfg) => of$(parseInt(cfg?.PostEditTimeLimit || '-1', 10))));
|
||||
const allowEditPost = observeConfigValue(database, 'AllowEditPost');
|
||||
const serverVersion = observeConfigValue(database, 'Version');
|
||||
const postEditTimeLimit = observeConfigIntValue(database, 'PostEditTimeLimit', -1);
|
||||
|
||||
const canPostPermission = combineLatest([channel, currentUser]).pipe(switchMap(([c, u]) => observePermissionForChannel(database, c, u, Permissions.CREATE_POST, false)));
|
||||
const hasAddReactionPermission = currentUser.pipe(switchMap((u) => observePermissionForPost(database, post, u, Permissions.ADD_REACTION, true)));
|
||||
|
|
@ -86,7 +85,7 @@ const enhanced = withObservables([], ({combinedPost, post, showAddReaction, loca
|
|||
return observePermissionForPost(database, post, u, isOwner ? Permissions.DELETE_POST : Permissions.DELETE_OTHERS_POSTS, false);
|
||||
}));
|
||||
|
||||
const experimentalTownSquareIsReadOnly = config.pipe(switchMap((value) => of$(value?.ExperimentalTownSquareIsReadOnly === 'true')));
|
||||
const experimentalTownSquareIsReadOnly = observeConfigBooleanValue(database, 'ExperimentalTownSquareIsReadOnly');
|
||||
const channelIsReadOnly = combineLatest([currentUser, channel, experimentalTownSquareIsReadOnly]).pipe(switchMap(([u, c, readOnly]) => {
|
||||
return of$(c?.name === General.DEFAULT_CHANNEL && (u && !isSystemAdmin(u.roles)) && readOnly);
|
||||
}));
|
||||
|
|
@ -98,7 +97,7 @@ const enhanced = withObservables([], ({combinedPost, post, showAddReaction, loca
|
|||
|
||||
const canEditUntil = combineLatest([isLicensed, allowEditPost, postEditTimeLimit, serverVersion, channelIsArchived, channelIsReadOnly]).pipe(
|
||||
switchMap(([ls, alw, limit, semVer, isArchived, isReadOnly]) => {
|
||||
if (!isArchived && !isReadOnly && ls && ((alw === Permissions.ALLOW_EDIT_POST_TIME_LIMIT && !isMinimumServerVersion(semVer, 6)) || (limit !== -1))) {
|
||||
if (!isArchived && !isReadOnly && ls && ((alw === Permissions.ALLOW_EDIT_POST_TIME_LIMIT && !isMinimumServerVersion(semVer || '', 6)) || (limit !== -1))) {
|
||||
return of$(post.createAt + (limit * (1000)));
|
||||
}
|
||||
return of$(-1);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChannelModel} from '@app/database/models/server';
|
||||
import {ChannelModel} from '@database/models/server';
|
||||
import {fileToGalleryItem} from '@utils/gallery';
|
||||
|
||||
export const getNumberFileMenuOptions = (canDownloadFiles: boolean, publicLinkEnabled: boolean) => {
|
||||
|
|
|
|||
|
|
@ -111,10 +111,6 @@ export function getUtcOffsetForTimeZone(timezone: string) {
|
|||
return moment.tz(timezone).utcOffset();
|
||||
}
|
||||
|
||||
export function isCustomStatusExpirySupported(version: string) {
|
||||
return isMinimumServerVersion(version, 5, 37);
|
||||
}
|
||||
|
||||
export function toTitleCase(str: string) {
|
||||
function doTitleCase(txt: string) {
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
|
|
|
|||
|
|
@ -6,21 +6,20 @@ import {getPreferenceValue} from '@helpers/api/preference';
|
|||
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
|
||||
export function processIsCRTEnabled(preferences: PreferenceModel[]|PreferenceType[], config?: ClientConfig): boolean {
|
||||
export function processIsCRTEnabled(preferences: PreferenceModel[]|PreferenceType[], configValue?: string, featureFlag?: string): boolean {
|
||||
let preferenceDefault = Preferences.COLLAPSED_REPLY_THREADS_OFF;
|
||||
const configValue = config?.CollapsedThreads;
|
||||
if (configValue === Config.DEFAULT_ON) {
|
||||
preferenceDefault = Preferences.COLLAPSED_REPLY_THREADS_ON;
|
||||
}
|
||||
const preference = getPreferenceValue(preferences, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSED_REPLY_THREADS, preferenceDefault);
|
||||
|
||||
const isAllowed = (
|
||||
config?.FeatureFlagCollapsedThreads === Config.TRUE &&
|
||||
config?.CollapsedThreads !== Config.DISABLED
|
||||
featureFlag === Config.TRUE &&
|
||||
configValue !== Config.DISABLED
|
||||
);
|
||||
|
||||
return isAllowed && (
|
||||
preference === Preferences.COLLAPSED_REPLY_THREADS_ON ||
|
||||
config?.CollapsedThreads === Config.ALWAYS_ON
|
||||
configValue === Config.ALWAYS_ON
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,19 +10,18 @@ import Foundation
|
|||
import SQLite
|
||||
|
||||
extension Database {
|
||||
public func getConfig(_ serverUrl: String) -> [String: Any]? {
|
||||
public func getConfig(_ serverUrl: String, _ key: String) -> String? {
|
||||
do {
|
||||
let db = try getDatabaseForServer(serverUrl)
|
||||
let id = Expression<String>("id")
|
||||
let value = Expression<String>("value")
|
||||
let query = systemTable.select(value).filter(id == "config")
|
||||
var json: [String: Any]? = nil
|
||||
let query = configTable.select(value).filter(id == key)
|
||||
if let result = try db.pluck(query) {
|
||||
let val = try result.get(value)
|
||||
json = try? JSONSerialization.jsonObject(with: val.data(using: .utf8)!, options: []) as? [String: Any]
|
||||
return val
|
||||
}
|
||||
|
||||
return json
|
||||
return nil
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public class Database: NSObject {
|
|||
internal var userTable = Table("User")
|
||||
internal var threadTable = Table("Thread")
|
||||
internal var threadParticipantTable = Table("ThreadParticipant")
|
||||
internal var configTable = Table("Config")
|
||||
|
||||
@objc public static let `default` = Database()
|
||||
|
||||
|
|
|
|||
|
|
@ -31,23 +31,25 @@ class ServerService: ObservableObject {
|
|||
|
||||
private func updateServerSettings(_ server: ServerModel?) -> ServerModel? {
|
||||
if var s = server {
|
||||
if let config = Gekidou.Database.default.getConfig(s.url) {
|
||||
let fileSize = Gekidou.Database.default.getConfig(s.url, "MaxFileSize")
|
||||
let postSize = Gekidou.Database.default.getConfig(s.url, "MaxPostSize")
|
||||
let mobileFileUpload = Gekidou.Database.default.getConfig(s.url, "EnableMobileFileUpload")
|
||||
|
||||
let hasChannels = Gekidou.Database.default.serverHasChannels(s.url)
|
||||
|
||||
var maxFileSize: Int64? = nil
|
||||
if let fileSize = config["MaxFileSize"] as? String {
|
||||
maxFileSize = Int64(fileSize)
|
||||
if let value = fileSize {
|
||||
maxFileSize = Int64(value)
|
||||
}
|
||||
|
||||
var maxPostSize: Int64? = nil
|
||||
if let length = config["MaxPostSize"] as? String {
|
||||
maxPostSize = Int64(length)
|
||||
if let value = postSize {
|
||||
maxPostSize = Int64(value)
|
||||
}
|
||||
|
||||
let uploadsEnabled = config["EnableMobileFileUpload"] as? String == "true"
|
||||
let uploadsEnabled = mobileFileUpload == "true"
|
||||
s.updateSettings(hasChannels, maxPostSize, maxFileSize, uploadsEnabled)
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ class TestHelper {
|
|||
});
|
||||
|
||||
const systems = await prepareCommonSystemValues(operator, {
|
||||
config: {} as ClientConfig,
|
||||
license: {} as ClientLicense,
|
||||
currentChannelId: '',
|
||||
currentTeamId: this.basicTeam!.id,
|
||||
|
|
|
|||
|
|
@ -194,6 +194,11 @@ export type HandleSystemArgs = PrepareOnly & {
|
|||
systems?: IdValue[];
|
||||
}
|
||||
|
||||
export type HandleConfigArgs = PrepareOnly & {
|
||||
configs: IdValue[];
|
||||
configsToDelete: IdValue[];
|
||||
}
|
||||
|
||||
export type HandleMyChannelArgs = PrepareOnly & {
|
||||
channels?: Channel[];
|
||||
myChannels?: ChannelMembership[];
|
||||
|
|
|
|||
18
types/database/models/servers/config.ts
Normal file
18
types/database/models/servers/config.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
/**
|
||||
* The Config model is another set of key-value pair combination but this one
|
||||
* will hold the server configuration.
|
||||
*/
|
||||
declare class ConfigModel extends Model {
|
||||
/** table (name) : Config */
|
||||
static table: string;
|
||||
|
||||
/** value : The value for that config/information and whose key will be the id column */
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default ConfigModel;
|
||||
Loading…
Reference in a new issue