Refactor entry to better share between rest and GQL (#6638)
* Refactor entry to better share between rest and GQL * Address feedback
This commit is contained in:
parent
a32022ba5c
commit
260e1cfde7
10 changed files with 328 additions and 389 deletions
41
app/actions/local/systems.ts
Normal file
41
app/actions/local/systems.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
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 {logError} from '@utils/log';
|
||||
|
||||
export async function storeConfigAndLicense(serverUrl: string, config: ClientConfig, license: ClientLicense) {
|
||||
try {
|
||||
// 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 systems: IdValue[] = [];
|
||||
if (!deepEqual(config, current.config)) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.CONFIG,
|
||||
value: JSON.stringify(config),
|
||||
});
|
||||
}
|
||||
|
||||
if (!deepEqual(license, current.license)) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.LICENSE,
|
||||
value: JSON.stringify(license),
|
||||
});
|
||||
}
|
||||
|
||||
if (systems.length) {
|
||||
await operator.handleSystem({systems, prepareRecordsOnly: false});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logError('An error occurred while saving config & license', error);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,14 +4,14 @@
|
|||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {prepareCommonSystemValues, getCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, setCurrentTeamAndChannelId, getConfig, getCurrentChannelId} from '@queries/servers/system';
|
||||
import {prepareCommonSystemValues, getCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, setCurrentTeamAndChannelId, getCurrentChannelId} from '@queries/servers/system';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {deleteV1Data} from '@utils/file';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug, logInfo} from '@utils/log';
|
||||
import {logInfo} from '@utils/log';
|
||||
|
||||
import {deferredAppEntryActions, entry, registerDeviceToken, syncOtherServers, verifyPushProxy} from './common';
|
||||
import {graphQLCommon} from './gql_common';
|
||||
import {registerDeviceToken, syncOtherServers, verifyPushProxy} from './common';
|
||||
import {deferredAppEntryActions, entry} from './gql_common';
|
||||
|
||||
export async function appEntry(serverUrl: string, since = 0, isUpgrade = false) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
|
|
@ -19,8 +19,6 @@ export async function appEntry(serverUrl: string, since = 0, isUpgrade = false)
|
|||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
const {database} = operator;
|
||||
|
||||
if (!since) {
|
||||
registerDeviceToken(serverUrl);
|
||||
}
|
||||
|
|
@ -31,34 +29,6 @@ export async function appEntry(serverUrl: string, since = 0, isUpgrade = false)
|
|||
operator.batchRecords(removeLastUnreadChannelId);
|
||||
}
|
||||
|
||||
const config = await getConfig(database);
|
||||
let result;
|
||||
if (config?.FeatureFlagGraphQL === 'true') {
|
||||
const {currentTeamId, currentChannelId} = await getCommonSystemValues(database);
|
||||
result = await graphQLCommon(serverUrl, true, currentTeamId, currentChannelId, '', isUpgrade);
|
||||
if (result.error) {
|
||||
logDebug('Error using GraphQL, trying REST', result.error);
|
||||
result = restAppEntry(serverUrl, since, isUpgrade);
|
||||
}
|
||||
} else {
|
||||
result = restAppEntry(serverUrl, since, isUpgrade);
|
||||
}
|
||||
|
||||
if (!since) {
|
||||
// Load data from other servers
|
||||
syncOtherServers(serverUrl);
|
||||
}
|
||||
|
||||
verifyPushProxy(serverUrl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function restAppEntry(serverUrl: string, since = 0, isUpgrade = false) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
const {database} = operator;
|
||||
|
||||
const tabletDevice = await isTablet();
|
||||
|
|
@ -98,6 +68,13 @@ async function restAppEntry(serverUrl: string, since = 0, isUpgrade = false) {
|
|||
const {config, license} = await getCommonSystemValues(database);
|
||||
await deferredAppEntryActions(serverUrl, lastDisconnectedAt, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, initialTeamId, switchToChannel ? initialChannelId : undefined);
|
||||
|
||||
if (!since) {
|
||||
// Load data from other servers
|
||||
syncOtherServers(serverUrl);
|
||||
}
|
||||
|
||||
verifyPushProxy(serverUrl);
|
||||
|
||||
return {userId: currentUserId};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Model} from '@nozbe/watermelondb';
|
||||
import {Database, Model} from '@nozbe/watermelondb';
|
||||
|
||||
import {fetchMissingDirectChannelsInfo, fetchMyChannelsForTeam, MyChannelsRequest, switchToChannelById} from '@actions/remote/channel';
|
||||
import {fetchMissingDirectChannelsInfo, fetchMyChannelsForTeam, MyChannelsRequest} from '@actions/remote/channel';
|
||||
import {fetchGroupsForMember} from '@actions/remote/groups';
|
||||
import {fetchPostsForUnreadChannels} from '@actions/remote/post';
|
||||
import {MyPreferencesRequest, fetchMyPreferences} from '@actions/remote/preference';
|
||||
import {fetchRoles} from '@actions/remote/role';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
import {fetchAllTeams, fetchMyTeams, fetchTeamsChannelsAndUnreadPosts, MyTeamsRequest} from '@actions/remote/team';
|
||||
import {fetchAndSwitchToThread, fetchNewThreads} from '@actions/remote/thread';
|
||||
import {fetchNewThreads} from '@actions/remote/thread';
|
||||
import {fetchMe, MyUserRequest, updateAllUsersSince} from '@actions/remote/user';
|
||||
import {gqlAllChannels} from '@client/graphQL/entry';
|
||||
import {Preferences, Screens} from '@constants';
|
||||
import {General, Preferences, Screens} from '@constants';
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_RESPONSE_UNKNOWN, PUSH_PROXY_STATUS_NOT_AVAILABLE, PUSH_PROXY_STATUS_UNKNOWN, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
|
||||
import DatabaseManager from '@database/manager';
|
||||
|
|
@ -22,22 +23,16 @@ import {DEFAULT_LOCALE} from '@i18n';
|
|||
import NetworkManager from '@managers/network_manager';
|
||||
import {getDeviceToken} from '@queries/app/global';
|
||||
import {queryAllServers} from '@queries/app/servers';
|
||||
import {getMyChannel, prepareMyChannelsForTeam, queryAllChannelsForTeam, queryChannelsById} from '@queries/servers/channel';
|
||||
import {prepareMyChannelsForTeam, queryAllChannelsForTeam, queryChannelsById} from '@queries/servers/channel';
|
||||
import {prepareModels, truncateCrtRelatedTables} from '@queries/servers/entry';
|
||||
import {getHasCRTChanged} from '@queries/servers/preference';
|
||||
import {getConfig, getCurrentUserId, getPushVerificationStatus, getWebSocketLastDisconnected, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {deleteMyTeams, getAvailableTeamIds, getMyTeamById, getNthLastChannelFromTeam, queryMyTeams, queryMyTeamsByIds, queryTeamsById} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled} from '@queries/servers/thread';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {isDMorGM} from '@utils/channel';
|
||||
import {getConfig, getCurrentUserId, getPushVerificationStatus, getWebSocketLastDisconnected} from '@queries/servers/system';
|
||||
import {deleteMyTeams, getAvailableTeamIds, getTeamChannelHistory, queryMyTeams, queryMyTeamsByIds, queryTeamsById} from '@queries/servers/team';
|
||||
import {isDMorGM, sortChannelsByDisplayName} from '@utils/channel';
|
||||
import {getMemberChannelsFromGQLQuery, gqlToClientChannelMembership} from '@utils/graphql';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug} from '@utils/log';
|
||||
import {emitNotificationError} from '@utils/notification';
|
||||
import {processIsCRTEnabled} from '@utils/thread';
|
||||
|
||||
import {fetchGroupsForMember} from '../groups';
|
||||
|
||||
import type ClientError from '@client/rest/error';
|
||||
|
||||
export type AppEntryData = {
|
||||
|
|
@ -91,7 +86,7 @@ export const teamsToRemove = async (serverUrl: string, removeTeamIds?: string[])
|
|||
return [];
|
||||
};
|
||||
|
||||
export const entry = async (serverUrl: string, teamId?: string, channelId?: string, since = 0): Promise<EntryResponse> => {
|
||||
export const entryRest = async (serverUrl: string, teamId?: string, channelId?: string, since = 0): Promise<EntryResponse> => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
|
|
@ -114,13 +109,7 @@ export const entry = async (serverUrl: string, teamId?: string, channelId?: stri
|
|||
|
||||
const rolesData = await fetchRoles(serverUrl, teamData.memberships, chData?.memberships, meData.user, true);
|
||||
|
||||
let initialChannelId = channelId;
|
||||
if (!chData?.channels?.find((c) => c.id === channelId)) {
|
||||
initialChannelId = '';
|
||||
}
|
||||
if (initialTeamId !== teamId || !initialChannelId) {
|
||||
initialChannelId = await getNthLastChannelFromTeam(database, initialTeamId);
|
||||
}
|
||||
const initialChannelId = await entryInitialChannelId(database, channelId, teamId, initialTeamId, meData?.user?.locale || '', chData?.channels, chData?.memberships);
|
||||
|
||||
const removeTeams = await teamsToRemove(serverUrl, removeTeamIds);
|
||||
|
||||
|
|
@ -279,7 +268,45 @@ export const fetchAlternateTeamData = async (
|
|||
return {initialTeamId, removeTeamIds};
|
||||
};
|
||||
|
||||
export async function deferredAppEntryActions(
|
||||
export async function entryInitialChannelId(database: Database, requestedChannelId = '', requestedTeamId = '', initialTeamId: string, locale: string, channels?: Channel[], memberships?: ChannelMember[]) {
|
||||
const membershipIds = new Set(memberships?.map((m) => m.channel_id));
|
||||
const requestedChannel = channels?.find((c) => (c.id === requestedChannelId) && membershipIds.has(c.id));
|
||||
|
||||
// If team and channel are the requested, return the channel
|
||||
if (initialTeamId === requestedTeamId && requestedChannel) {
|
||||
return requestedChannelId;
|
||||
}
|
||||
|
||||
// DM or GMs don't care about changes in teams, so return directly
|
||||
if (requestedChannel && isDMorGM(requestedChannel)) {
|
||||
return requestedChannelId;
|
||||
}
|
||||
|
||||
// Check if we are still members of any channel on the history
|
||||
const teamChannelHistory = await getTeamChannelHistory(database, initialTeamId);
|
||||
for (const c of teamChannelHistory) {
|
||||
if (membershipIds.has(c) || c === Screens.GLOBAL_THREADS) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are member of the default channel.
|
||||
const defaultChannel = channels?.find((c) => c.name === General.DEFAULT_CHANNEL && c.team_id === initialTeamId);
|
||||
const iAmMemberOfTheTeamDefaultChannel = Boolean(defaultChannel && membershipIds.has(defaultChannel.id));
|
||||
if (iAmMemberOfTheTeamDefaultChannel) {
|
||||
return defaultChannel!.id;
|
||||
}
|
||||
|
||||
// Get the first channel of the list, based on the locale.
|
||||
const myFirstTeamChannel = channels?.filter((c) =>
|
||||
c.team_id === requestedTeamId &&
|
||||
c.type === General.OPEN_CHANNEL &&
|
||||
membershipIds.has(c.id),
|
||||
).sort(sortChannelsByDisplayName.bind(null, locale))[0];
|
||||
return myFirstTeamChannel?.id || '';
|
||||
}
|
||||
|
||||
export async function restDeferredAppEntryActions(
|
||||
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig, license: ClientLicense, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
initialTeamId?: string, initialChannelId?: string) {
|
||||
|
|
@ -486,61 +513,3 @@ export async function verifyPushProxy(serverUrl: string) {
|
|||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleNotificationNavigation(serverUrl: string, selectedChannelId: string, selectedTeamId: string, notificationChannelId: string, notificationTeamId: string, rootId = '') {
|
||||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const myChannel = await getMyChannel(database, selectedChannelId);
|
||||
const myTeam = await getMyTeamById(database, selectedTeamId);
|
||||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
const isThreadNotification = isCRTEnabled && Boolean(rootId);
|
||||
|
||||
let switchedToScreen = false;
|
||||
let switchedToChannel = false;
|
||||
if (myChannel && myTeam) {
|
||||
if (isThreadNotification) {
|
||||
await fetchAndSwitchToThread(serverUrl, rootId, true);
|
||||
} else {
|
||||
switchedToChannel = true;
|
||||
await switchToChannelById(serverUrl, selectedChannelId, selectedTeamId);
|
||||
}
|
||||
switchedToScreen = true;
|
||||
}
|
||||
|
||||
if (!switchedToScreen) {
|
||||
const isTabletDevice = await isTablet();
|
||||
if (isTabletDevice || (notificationChannelId === selectedChannelId)) {
|
||||
// Make switch again to get the missing data and make sure the team is the correct one
|
||||
switchedToScreen = true;
|
||||
if (isThreadNotification) {
|
||||
await fetchAndSwitchToThread(serverUrl, rootId, true);
|
||||
} else {
|
||||
switchedToChannel = true;
|
||||
await switchToChannelById(serverUrl, notificationChannelId, notificationTeamId);
|
||||
}
|
||||
} else if (notificationTeamId !== selectedTeamId || notificationChannelId !== selectedChannelId) {
|
||||
// If in the end the selected team or channel is different than the one from the notification
|
||||
// we switch again
|
||||
await setCurrentTeamAndChannelId(operator, selectedTeamId, selectedChannelId);
|
||||
}
|
||||
}
|
||||
|
||||
if (notificationTeamId !== selectedTeamId) {
|
||||
emitNotificationError('Team');
|
||||
} else if (notificationChannelId !== selectedChannelId) {
|
||||
emitNotificationError('Channel');
|
||||
}
|
||||
|
||||
// Waiting for the screen to display fixes a race condition when fetching and storing data
|
||||
if (switchedToChannel) {
|
||||
await NavigationStore.waitUntilScreenHasLoaded(Screens.CHANNEL);
|
||||
} else if (switchedToScreen && isThreadNotification) {
|
||||
await NavigationStore.waitUntilScreenHasLoaded(Screens.THREAD);
|
||||
}
|
||||
|
||||
return {};
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
import {Database} from '@nozbe/watermelondb';
|
||||
|
||||
import {markChannelAsRead, MyChannelsRequest} from '@actions/remote/channel';
|
||||
import {storeConfigAndLicense} from '@actions/local/systems';
|
||||
import {MyChannelsRequest} from '@actions/remote/channel';
|
||||
import {fetchGroupsForMember} from '@actions/remote/groups';
|
||||
import {fetchPostsForChannel, fetchPostsForUnreadChannels} from '@actions/remote/post';
|
||||
import {fetchPostsForUnreadChannels} from '@actions/remote/post';
|
||||
import {MyTeamsRequest} from '@actions/remote/team';
|
||||
import {fetchNewThreads} from '@actions/remote/thread';
|
||||
import {MyUserRequest, updateAllUsersSince} from '@actions/remote/user';
|
||||
import {updateAllUsersSince} from '@actions/remote/user';
|
||||
import {gqlEntry, gqlEntryChannels, gqlOtherChannels} from '@client/graphQL/entry';
|
||||
import {Preferences} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
|
|
@ -17,14 +18,13 @@ import {selectDefaultTeam} from '@helpers/api/team';
|
|||
import {queryAllChannels, queryAllChannelsForTeam} from '@queries/servers/channel';
|
||||
import {prepareModels, truncateCrtRelatedTables} from '@queries/servers/entry';
|
||||
import {getHasCRTChanged} from '@queries/servers/preference';
|
||||
import {prepareCommonSystemValues} from '@queries/servers/system';
|
||||
import {addChannelToTeamHistory, addTeamToTeamHistory, queryMyTeams} from '@queries/servers/team';
|
||||
import {selectDefaultChannelForTeam} from '@utils/channel';
|
||||
import {getConfig} from '@queries/servers/system';
|
||||
import {queryMyTeams} from '@queries/servers/team';
|
||||
import {filterAndTransformRoles, getMemberChannelsFromGQLQuery, getMemberTeamsFromGQLQuery, gqlToClientChannelMembership, gqlToClientPreference, gqlToClientSidebarCategory, gqlToClientTeamMembership, gqlToClientUser} from '@utils/graphql';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug} from '@utils/log';
|
||||
import {processIsCRTEnabled} from '@utils/thread';
|
||||
|
||||
import {teamsToRemove, FETCH_UNREADS_TIMEOUT, handleNotificationNavigation} from './common';
|
||||
import {teamsToRemove, FETCH_UNREADS_TIMEOUT, entryRest, EntryResponse, entryInitialChannelId, restDeferredAppEntryActions} from './common';
|
||||
|
||||
import type ClientError from '@client/rest/error';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
|
|
@ -33,14 +33,13 @@ import type TeamModel from '@typings/database/models/servers/team';
|
|||
export async function deferredAppEntryGraphQLActions(
|
||||
serverUrl: string,
|
||||
since: number,
|
||||
meData: MyUserRequest,
|
||||
currentUserId: string,
|
||||
teamData: MyTeamsRequest,
|
||||
chData: MyChannelsRequest | undefined,
|
||||
isTabletDevice: boolean,
|
||||
preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig,
|
||||
initialTeamId?: string,
|
||||
initialChannelId?: string,
|
||||
isCRTEnabled = false,
|
||||
syncDatabase?: boolean,
|
||||
) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
|
|
@ -48,12 +47,6 @@ export async function deferredAppEntryGraphQLActions(
|
|||
}
|
||||
const {database} = operator;
|
||||
|
||||
// defer fetching posts for initial channel
|
||||
if (initialChannelId && isTabletDevice) {
|
||||
fetchPostsForChannel(serverUrl, initialChannelId);
|
||||
markChannelAsRead(serverUrl, initialChannelId);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (chData?.channels?.length && chData.memberships?.length) {
|
||||
// defer fetching posts for unread channels on initial team
|
||||
|
|
@ -61,7 +54,7 @@ export async function deferredAppEntryGraphQLActions(
|
|||
}
|
||||
}, FETCH_UNREADS_TIMEOUT);
|
||||
|
||||
if (isCRTEnabled) {
|
||||
if (preferences && processIsCRTEnabled(preferences, config)) {
|
||||
if (initialTeamId) {
|
||||
await fetchNewThreads(serverUrl, initialTeamId, false);
|
||||
}
|
||||
|
|
@ -77,16 +70,19 @@ export async function deferredAppEntryGraphQLActions(
|
|||
}
|
||||
|
||||
if (initialTeamId) {
|
||||
const result = await getChannelData(serverUrl, initialTeamId, meData.user!.id, true);
|
||||
const result = await getChannelData(serverUrl, initialTeamId, currentUserId, true);
|
||||
if ('error' in result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const removeChannels = await getRemoveChannels(database, result.chData, initialTeamId, false, syncDatabase);
|
||||
const removeChannels = await getRemoveChannels(database, result.chData, initialTeamId, false);
|
||||
|
||||
const modelPromises = await prepareModels({operator, removeChannels, chData: result.chData}, true);
|
||||
|
||||
modelPromises.push(operator.handleRole({roles: filterAndTransformRoles(result.roles), prepareRecordsOnly: true}));
|
||||
const roles = filterAndTransformRoles(result.roles);
|
||||
if (roles.length) {
|
||||
modelPromises.push(operator.handleRole({roles, prepareRecordsOnly: true}));
|
||||
}
|
||||
const models = (await Promise.all(modelPromises)).flat();
|
||||
operator.batchRecords(models);
|
||||
|
||||
|
|
@ -98,30 +94,26 @@ export async function deferredAppEntryGraphQLActions(
|
|||
}, FETCH_UNREADS_TIMEOUT);
|
||||
}
|
||||
|
||||
if (meData.user?.id) {
|
||||
// Fetch groups for current user
|
||||
fetchGroupsForMember(serverUrl, meData.user?.id);
|
||||
}
|
||||
// Fetch groups for current user
|
||||
fetchGroupsForMember(serverUrl, currentUserId);
|
||||
|
||||
updateAllUsersSince(serverUrl, since);
|
||||
|
||||
return {};
|
||||
return {error: undefined};
|
||||
}
|
||||
|
||||
const getRemoveChannels = async (database: Database, chData: MyChannelsRequest | undefined, initialTeamId: string, singleTeam: boolean, syncDatabase?: boolean) => {
|
||||
const getRemoveChannels = async (database: Database, chData: MyChannelsRequest | undefined, initialTeamId: string, singleTeam: boolean) => {
|
||||
const removeChannels: ChannelModel[] = [];
|
||||
if (syncDatabase) {
|
||||
if (chData?.channels) {
|
||||
const fetchedChannelIds = chData.channels?.map((channel) => channel.id);
|
||||
if (chData?.channels) {
|
||||
const fetchedChannelIds = chData.channels?.map((channel) => channel.id);
|
||||
|
||||
const query = singleTeam ? queryAllChannelsForTeam(database, initialTeamId) : queryAllChannels(database);
|
||||
const channels = await query.fetch();
|
||||
const query = singleTeam ? queryAllChannelsForTeam(database, initialTeamId) : queryAllChannels(database);
|
||||
const channels = await query.fetch();
|
||||
|
||||
for (const channel of channels) {
|
||||
const excludeCondition = singleTeam ? true : channel.teamId !== initialTeamId && channel.teamId !== '';
|
||||
if (excludeCondition && !fetchedChannelIds?.includes(channel.id)) {
|
||||
removeChannels.push(channel);
|
||||
}
|
||||
for (const channel of channels) {
|
||||
const excludeCondition = singleTeam ? true : channel.teamId !== initialTeamId && channel.teamId !== '';
|
||||
if (excludeCondition && !fetchedChannelIds?.includes(channel.id)) {
|
||||
removeChannels.push(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -158,17 +150,13 @@ const getChannelData = async (serverUrl: string, initialTeamId: string, userId:
|
|||
return {chData, roles};
|
||||
};
|
||||
|
||||
export const graphQLCommon = async (serverUrl: string, syncDatabase: boolean, currentTeamId: string, currentChannelId: string, rootId?: string, isUpgrade = false, isNotificationEntry = false) => {
|
||||
const dt = Date.now();
|
||||
|
||||
export const entryGQL = async (serverUrl: string, currentTeamId?: string, currentChannelId?: string): Promise<EntryResponse> => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
const {database} = operator;
|
||||
|
||||
const isTabletDevice = await isTablet();
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await gqlEntry(serverUrl);
|
||||
|
|
@ -188,6 +176,7 @@ export const graphQLCommon = async (serverUrl: string, syncDatabase: boolean, cu
|
|||
|
||||
const config = fetchedData.config || {} as ClientConfig;
|
||||
const license = fetchedData.license || {} as ClientLicense;
|
||||
await storeConfigAndLicense(serverUrl, config, license);
|
||||
|
||||
const meData = {
|
||||
user: gqlToClientUser(fetchedData.user!),
|
||||
|
|
@ -212,13 +201,6 @@ export const graphQLCommon = async (serverUrl: string, syncDatabase: boolean, cu
|
|||
}
|
||||
}
|
||||
|
||||
if (isUpgrade && meData?.user) {
|
||||
const me = await prepareCommonSystemValues(operator, {currentUserId: meData.user.id});
|
||||
if (me?.length) {
|
||||
await operator.batchRecords(me);
|
||||
}
|
||||
}
|
||||
|
||||
let initialTeamId = currentTeamId;
|
||||
if (!teamData.teams.length) {
|
||||
initialTeamId = '';
|
||||
|
|
@ -244,72 +226,64 @@ export const graphQLCommon = async (serverUrl: string, syncDatabase: boolean, cu
|
|||
|
||||
const roles = filterAndTransformRoles(gqlRoles);
|
||||
|
||||
let initialChannelId = currentChannelId;
|
||||
if (initialTeamId !== currentTeamId || !chData?.channels?.find((c) => c.id === currentChannelId)) {
|
||||
initialChannelId = '';
|
||||
if (isTabletDevice && chData?.channels && chData.memberships) {
|
||||
initialChannelId = selectDefaultChannelForTeam(chData.channels, chData.memberships, initialTeamId, roles, meData.user.locale)?.id || '';
|
||||
}
|
||||
}
|
||||
|
||||
const initialChannelId = await entryInitialChannelId(database, currentChannelId, currentTeamId, initialTeamId, meData.user.id, chData?.channels, chData?.memberships);
|
||||
let removeTeams: TeamModel[] = [];
|
||||
const removeChannels = await getRemoveChannels(database, chData, initialTeamId, true, syncDatabase);
|
||||
const removeChannels = await getRemoveChannels(database, chData, initialTeamId, true);
|
||||
|
||||
if (syncDatabase) {
|
||||
const removeTeamIds = [];
|
||||
const removeTeamIds = [];
|
||||
|
||||
const removedFromTeam = teamData.memberships?.filter((m) => m.delete_at > 0);
|
||||
if (removedFromTeam?.length) {
|
||||
removeTeamIds.push(...removedFromTeam.map((m) => m.team_id));
|
||||
}
|
||||
|
||||
if (teamData.teams?.length === 0) {
|
||||
// User is no longer a member of any team
|
||||
const myTeams = await queryMyTeams(database).fetch();
|
||||
removeTeamIds.push(...(myTeams?.map((myTeam) => myTeam.id) || []));
|
||||
}
|
||||
|
||||
removeTeams = await teamsToRemove(serverUrl, removeTeamIds);
|
||||
const removedFromTeam = teamData.memberships?.filter((m) => m.delete_at > 0);
|
||||
if (removedFromTeam?.length) {
|
||||
removeTeamIds.push(...removedFromTeam.map((m) => m.team_id));
|
||||
}
|
||||
|
||||
if (teamData.teams?.length === 0) {
|
||||
// User is no longer a member of any team
|
||||
const myTeams = await queryMyTeams(database).fetch();
|
||||
removeTeamIds.push(...(myTeams?.map((myTeam) => myTeam.id) || []));
|
||||
}
|
||||
|
||||
removeTeams = await teamsToRemove(serverUrl, removeTeamIds);
|
||||
|
||||
const modelPromises = await prepareModels({operator, initialTeamId, removeTeams, removeChannels, teamData, chData, prefData, meData}, true);
|
||||
modelPromises.push(operator.handleRole({roles, prepareRecordsOnly: true}));
|
||||
modelPromises.push(prepareCommonSystemValues(
|
||||
operator,
|
||||
{
|
||||
config,
|
||||
license,
|
||||
currentTeamId: initialTeamId,
|
||||
currentChannelId: initialChannelId,
|
||||
},
|
||||
));
|
||||
|
||||
if (initialTeamId && initialTeamId !== currentTeamId) {
|
||||
const th = addTeamToTeamHistory(operator, initialTeamId, true);
|
||||
modelPromises.push(th);
|
||||
if (roles.length) {
|
||||
modelPromises.push(operator.handleRole({roles, prepareRecordsOnly: true}));
|
||||
}
|
||||
|
||||
if (initialTeamId !== currentTeamId && initialChannelId) {
|
||||
try {
|
||||
const tch = addChannelToTeamHistory(operator, initialTeamId, initialChannelId, true);
|
||||
modelPromises.push(tch);
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
const models = await Promise.all(modelPromises);
|
||||
if (models.length) {
|
||||
await operator.batchRecords(models.flat());
|
||||
}
|
||||
|
||||
if (isNotificationEntry) {
|
||||
await handleNotificationNavigation(serverUrl, initialChannelId, initialTeamId, currentChannelId, currentTeamId, rootId);
|
||||
}
|
||||
|
||||
const isCRTEnabled = Boolean(prefData.preferences && processIsCRTEnabled(prefData.preferences, config));
|
||||
deferredAppEntryGraphQLActions(serverUrl, 0, meData, teamData, chData, isTabletDevice, initialTeamId, initialChannelId, isCRTEnabled, syncDatabase);
|
||||
|
||||
const timeElapsed = Date.now() - dt;
|
||||
return {time: timeElapsed, hasTeams: Boolean(teamData.teams.length), userId: meData.user.id, error: undefined};
|
||||
const models = (await Promise.all(modelPromises)).flat();
|
||||
return {models, initialTeamId, initialChannelId, prefData, teamData, chData, meData};
|
||||
};
|
||||
|
||||
export const entry = async (serverUrl: string, teamId?: string, channelId?: string, since = 0): Promise<EntryResponse> => {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const config = await getConfig(database);
|
||||
let result;
|
||||
if (config?.FeatureFlagGraphQL === 'true') {
|
||||
result = await entryGQL(serverUrl, teamId, channelId);
|
||||
if ('error' in result) {
|
||||
logDebug('Error using GraphQL, trying REST', result.error);
|
||||
result = entryRest(serverUrl, teamId, channelId, since);
|
||||
}
|
||||
} else {
|
||||
result = entryRest(serverUrl, teamId, channelId, since);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export async function deferredAppEntryActions(
|
||||
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig, license: ClientLicense, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
initialTeamId?: string, initialChannelId?: string) {
|
||||
let result;
|
||||
if (config?.FeatureFlagGraphQL === 'true') {
|
||||
result = await deferredAppEntryGraphQLActions(serverUrl, since, currentUserId, teamData, chData, preferences, config, initialTeamId, initialChannelId);
|
||||
if (result.error) {
|
||||
logDebug('Error using GraphQL, trying REST', result.error);
|
||||
result = restDeferredAppEntryActions(serverUrl, since, currentUserId, currentUserLocale, preferences, config, license, teamData, chData, initialTeamId, initialChannelId);
|
||||
}
|
||||
} else {
|
||||
result = restDeferredAppEntryActions(serverUrl, since, currentUserId, currentUserLocale, preferences, config, license, teamData, chData, initialTeamId, initialChannelId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,15 @@
|
|||
|
||||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {getSessions} from '@actions/remote/session';
|
||||
import {ConfigAndLicenseRequest, fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import NetworkManager from '@managers/network_manager';
|
||||
import {setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug, logWarning} from '@utils/log';
|
||||
import {logWarning} from '@utils/log';
|
||||
import {scheduleExpiredNotification} from '@utils/notification';
|
||||
|
||||
import {deferredAppEntryActions, entry} from './common';
|
||||
import {graphQLCommon} from './gql_common';
|
||||
import {deferredAppEntryActions, entry} from './gql_common';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
|
||||
|
|
@ -22,13 +21,9 @@ type AfterLoginArgs = {
|
|||
deviceToken?: string;
|
||||
}
|
||||
|
||||
type SpecificAfterLoginArgs = {
|
||||
serverUrl: string;
|
||||
user: UserProfile;
|
||||
clData: ConfigAndLicenseRequest;
|
||||
}
|
||||
|
||||
export async function loginEntry({serverUrl, user, deviceToken}: AfterLoginArgs): Promise<{error?: any; hasTeams?: boolean; time?: number}> {
|
||||
const dt = Date.now();
|
||||
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
|
|
@ -50,7 +45,7 @@ export async function loginEntry({serverUrl, user, deviceToken}: AfterLoginArgs)
|
|||
}
|
||||
|
||||
try {
|
||||
const clData = await fetchConfigAndLicense(serverUrl, true);
|
||||
const clData = await fetchConfigAndLicense(serverUrl, false);
|
||||
if (clData.error) {
|
||||
return {error: clData.error};
|
||||
}
|
||||
|
|
@ -76,51 +71,32 @@ export async function loginEntry({serverUrl, user, deviceToken}: AfterLoginArgs)
|
|||
}
|
||||
}
|
||||
|
||||
if (clData.config?.FeatureFlagGraphQL === 'true') {
|
||||
const result = await graphQLCommon(serverUrl, false, '', '');
|
||||
if (!result.error) {
|
||||
return result;
|
||||
}
|
||||
logDebug('Error using GraphQL, trying REST', result.error);
|
||||
const entryData = await entry(serverUrl, '', '');
|
||||
|
||||
if ('error' in entryData) {
|
||||
return {error: entryData.error};
|
||||
}
|
||||
|
||||
return restLoginEntry({serverUrl, user, clData});
|
||||
const {models, initialTeamId, initialChannelId, prefData, teamData, chData} = entryData;
|
||||
|
||||
const isTabletDevice = await isTablet();
|
||||
|
||||
let switchToChannel = false;
|
||||
if (initialChannelId && isTabletDevice) {
|
||||
switchToChannel = true;
|
||||
switchToChannelById(serverUrl, initialChannelId, initialTeamId);
|
||||
} else {
|
||||
setCurrentTeamAndChannelId(operator, initialTeamId, '');
|
||||
}
|
||||
|
||||
await operator.batchRecords(models);
|
||||
|
||||
const config = clData.config || {} as ClientConfig;
|
||||
const license = clData.license || {} as ClientLicense;
|
||||
deferredAppEntryActions(serverUrl, 0, user.id, user.locale, prefData.preferences, config, license, teamData, chData, initialTeamId, switchToChannel ? initialChannelId : undefined);
|
||||
|
||||
return {time: Date.now() - dt, hasTeams: Boolean(teamData.teams?.length)};
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
}
|
||||
|
||||
const restLoginEntry = async ({serverUrl, user, clData}: SpecificAfterLoginArgs) => {
|
||||
const dt = Date.now();
|
||||
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
const entryData = await entry(serverUrl, '', '');
|
||||
|
||||
if ('error' in entryData) {
|
||||
return {error: entryData.error};
|
||||
}
|
||||
|
||||
const isTabletDevice = await isTablet();
|
||||
|
||||
const {models, initialTeamId, initialChannelId, prefData, teamData, chData} = entryData;
|
||||
|
||||
let switchToChannel = false;
|
||||
if (initialChannelId && isTabletDevice) {
|
||||
switchToChannel = true;
|
||||
switchToChannelById(serverUrl, initialChannelId, initialTeamId);
|
||||
} else {
|
||||
setCurrentTeamAndChannelId(operator, initialTeamId, '');
|
||||
}
|
||||
|
||||
await operator.batchRecords(models);
|
||||
|
||||
const config = clData.config || {} as ClientConfig;
|
||||
const license = clData.license || {} as ClientLicense;
|
||||
deferredAppEntryActions(serverUrl, 0, user.id, user.locale, prefData.preferences, config, license, teamData, chData, initialTeamId, switchToChannel ? initialChannelId : undefined);
|
||||
|
||||
return {time: Date.now() - dt, hasTeams: Boolean(teamData.teams?.length)};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,25 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {fetchAndSwitchToThread} from '@actions/remote/thread';
|
||||
import {Preferences, Screens} from '@constants';
|
||||
import {getDefaultThemeByAppearance} from '@context/theme';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getMyChannel} from '@queries/servers/channel';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {getCommonSystemValues, getConfig, getCurrentTeamId, getWebSocketLastDisconnected} from '@queries/servers/system';
|
||||
import {getCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {getMyTeamById} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {logDebug} from '@utils/log';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {emitNotificationError} from '@utils/notification';
|
||||
import {setThemeDefaults, updateThemeIfNeeded} from '@utils/theme';
|
||||
|
||||
import {deferredAppEntryActions, entry, handleNotificationNavigation, syncOtherServers} from './common';
|
||||
import {graphQLCommon} from './gql_common';
|
||||
import {syncOtherServers} from './common';
|
||||
import {deferredAppEntryActions, entry} from './gql_common';
|
||||
|
||||
export async function pushNotificationEntry(serverUrl: string, notification: NotificationWithData) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
|
|
@ -27,6 +33,8 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
const {database} = operator;
|
||||
const currentTeamId = await getCurrentTeamId(database);
|
||||
const currentServerUrl = await DatabaseManager.getActiveServerUrl();
|
||||
const lastDisconnectedAt = await getWebSocketLastDisconnected(database);
|
||||
|
||||
let isDirectChannel = false;
|
||||
|
||||
let teamId = notification.payload?.team_id;
|
||||
|
|
@ -54,30 +62,25 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
|
||||
await NavigationStore.waitUntilScreenHasLoaded(Screens.HOME);
|
||||
|
||||
const config = await getConfig(database);
|
||||
let result;
|
||||
if (config?.FeatureFlagGraphQL === 'true') {
|
||||
result = await graphQLCommon(serverUrl, true, teamId, channelId, rootId, false, true);
|
||||
if (result.error) {
|
||||
logDebug('Error using GraphQL, trying REST', result.error);
|
||||
result = restNotificationEntry(serverUrl, teamId, channelId, rootId, isDirectChannel);
|
||||
// To make the switch faster we determine if we already have the team & channel
|
||||
const myChannel = await getMyChannel(database, channelId);
|
||||
const myTeam = await getMyTeamById(database, teamId);
|
||||
|
||||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
const isThreadNotification = isCRTEnabled && Boolean(rootId);
|
||||
|
||||
let switchedToScreen = false;
|
||||
let switchedToChannel = false;
|
||||
if (myChannel && myTeam) {
|
||||
if (isThreadNotification) {
|
||||
await fetchAndSwitchToThread(serverUrl, rootId, true);
|
||||
} else {
|
||||
switchedToChannel = true;
|
||||
await switchToChannelById(serverUrl, channelId, teamId);
|
||||
}
|
||||
} else {
|
||||
result = restNotificationEntry(serverUrl, teamId, channelId, rootId, isDirectChannel);
|
||||
switchedToScreen = true;
|
||||
}
|
||||
|
||||
syncOtherServers(serverUrl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const restNotificationEntry = async (serverUrl: string, teamId: string, channelId: string, rootId: string, isDirectChannel: boolean) => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
const {database} = operator;
|
||||
|
||||
const entryData = await entry(serverUrl, teamId, channelId);
|
||||
if ('error' in entryData) {
|
||||
return {error: entryData.error};
|
||||
|
|
@ -99,16 +102,45 @@ const restNotificationEntry = async (serverUrl: string, teamId: string, channelI
|
|||
}
|
||||
}
|
||||
|
||||
await operator.batchRecords(models);
|
||||
if (!switchedToScreen) {
|
||||
const isTabletDevice = await isTablet();
|
||||
if (isTabletDevice || (channelId === selectedChannelId)) {
|
||||
// Make switch again to get the missing data and make sure the team is the correct one
|
||||
switchedToScreen = true;
|
||||
if (isThreadNotification) {
|
||||
await fetchAndSwitchToThread(serverUrl, rootId, true);
|
||||
} else {
|
||||
switchedToChannel = true;
|
||||
await switchToChannelById(serverUrl, channelId, teamId);
|
||||
}
|
||||
} else if (teamId !== selectedTeamId || channelId !== selectedChannelId) {
|
||||
// If in the end the selected team or channel is different than the one from the notification
|
||||
// we switch again
|
||||
await setCurrentTeamAndChannelId(operator, selectedTeamId, selectedChannelId);
|
||||
}
|
||||
}
|
||||
|
||||
await handleNotificationNavigation(serverUrl, selectedChannelId, selectedTeamId, channelId, teamId, rootId);
|
||||
if (teamId !== selectedTeamId) {
|
||||
emitNotificationError('Team');
|
||||
} else if (channelId !== selectedChannelId) {
|
||||
emitNotificationError('Channel');
|
||||
}
|
||||
|
||||
// Waiting for the screen to display fixes a race condition when fetching and storing data
|
||||
if (switchedToChannel) {
|
||||
await NavigationStore.waitUntilScreenHasLoaded(Screens.CHANNEL);
|
||||
} else if (switchedToScreen && isThreadNotification) {
|
||||
await NavigationStore.waitUntilScreenHasLoaded(Screens.THREAD);
|
||||
}
|
||||
|
||||
await operator.batchRecords(models);
|
||||
|
||||
const {id: currentUserId, locale: currentUserLocale} = (await getCurrentUser(operator.database))!;
|
||||
const {config, license} = await getCommonSystemValues(operator.database);
|
||||
|
||||
const lastDisconnectedAt = await getWebSocketLastDisconnected(database);
|
||||
|
||||
await deferredAppEntryActions(serverUrl, lastDisconnectedAt, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, selectedTeamId, selectedChannelId);
|
||||
|
||||
syncOtherServers(serverUrl);
|
||||
|
||||
return {userId: currentUserId};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ export const fetchGroupsForAutocomplete = async (serverUrl: string, query: strin
|
|||
const client: Client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.getGroups({query, includeMemberCount: true});
|
||||
|
||||
if (!response.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return operator.handleGroups({groups: response, prepareRecordsOnly: fetchOnly});
|
||||
} catch (error) {
|
||||
forceLogoutIfNecessary(serverUrl, error as ClientErrorProps);
|
||||
|
|
@ -51,6 +55,10 @@ export const fetchGroupsByNames = async (serverUrl: string, names: string[], fet
|
|||
const groups = (await Promise.all(promises)).flat();
|
||||
|
||||
// Save locally
|
||||
if (!groups.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return operator.handleGroups({groups, prepareRecordsOnly: fetchOnly});
|
||||
} catch (error) {
|
||||
forceLogoutIfNecessary(serverUrl, error as ClientErrorProps);
|
||||
|
|
@ -64,6 +72,10 @@ export const fetchGroupsForChannel = async (serverUrl: string, channelId: string
|
|||
const client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.getAllGroupsAssociatedToChannel(channelId);
|
||||
|
||||
if (!response.groups.length) {
|
||||
return {groups: [], groupChannels: []};
|
||||
}
|
||||
|
||||
const [groups, groupChannels] = await Promise.all([
|
||||
operator.handleGroups({groups: response.groups, prepareRecordsOnly: true}),
|
||||
operator.handleGroupChannelsForChannel({groups: response.groups, channelId, prepareRecordsOnly: true}),
|
||||
|
|
@ -87,6 +99,10 @@ export const fetchGroupsForTeam = async (serverUrl: string, teamId: string, fetc
|
|||
const client: Client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.getAllGroupsAssociatedToTeam(teamId);
|
||||
|
||||
if (!response.groups.length) {
|
||||
return {groups: [], groupTeams: []};
|
||||
}
|
||||
|
||||
const [groups, groupTeams] = await Promise.all([
|
||||
operator.handleGroups({groups: response.groups, prepareRecordsOnly: true}),
|
||||
operator.handleGroupTeamsForTeam({groups: response.groups, teamId, prepareRecordsOnly: true}),
|
||||
|
|
@ -109,6 +125,10 @@ export const fetchGroupsForMember = async (serverUrl: string, userId: string, fe
|
|||
const client: Client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.getAllGroupsAssociatedToMembership(userId);
|
||||
|
||||
if (!response.length) {
|
||||
return {groups: [], groupMemberships: []};
|
||||
}
|
||||
|
||||
const [groups, groupMemberships] = await Promise.all([
|
||||
operator.handleGroups({groups: response, prepareRecordsOnly: true}),
|
||||
operator.handleGroupMembershipsForMember({groups: response, userId, prepareRecordsOnly: true}),
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import deepEqual from 'deep-equal';
|
||||
|
||||
import {storeConfigAndLicense} from '@actions/local/systems';
|
||||
import {forceLogoutIfNecessary} from '@actions/remote/session';
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getServerCredentials} from '@init/credentials';
|
||||
import NetworkManager from '@managers/network_manager';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {logError} from '@utils/log';
|
||||
|
||||
import type ClientError from '@client/rest/error';
|
||||
|
|
@ -65,34 +62,8 @@ export const fetchConfigAndLicense = async (serverUrl: string, fetchOnly = false
|
|||
client.getClientLicenseOld(),
|
||||
]);
|
||||
|
||||
// If we have credentials for this server then update the values in the database
|
||||
if (!fetchOnly) {
|
||||
const credentials = await getServerCredentials(serverUrl);
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (credentials && operator) {
|
||||
const current = await getCommonSystemValues(operator.database);
|
||||
const systems: IdValue[] = [];
|
||||
if (!deepEqual(config, current.config)) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.CONFIG,
|
||||
value: JSON.stringify(config),
|
||||
});
|
||||
}
|
||||
|
||||
if (!deepEqual(license, current.license)) {
|
||||
systems.push({
|
||||
id: SYSTEM_IDENTIFIERS.LICENSE,
|
||||
value: JSON.stringify(license),
|
||||
});
|
||||
}
|
||||
|
||||
if (systems.length) {
|
||||
await operator.handleSystem({systems, prepareRecordsOnly: false}).
|
||||
catch((error) => {
|
||||
logError('An error occurred while saving config & license', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
storeConfigAndLicense(serverUrl, config, license);
|
||||
}
|
||||
|
||||
return {config, license};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {deferredAppEntryActions, entry} from '@actions/remote/entry/common';
|
||||
import {graphQLCommon} from '@actions/remote/entry/gql_common';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
import {deferredAppEntryActions, entry} from '@actions/remote/entry/gql_common';
|
||||
import {fetchStatusByIds} from '@actions/remote/user';
|
||||
import {loadConfigAndCalls} from '@calls/actions/calls';
|
||||
import {
|
||||
|
|
@ -29,7 +27,6 @@ import {isSupportedServerCalls} from '@calls/utils';
|
|||
import {Events, Screens, WebsocketEvents} from '@constants';
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import {getActiveServerUrl, queryActiveServer} from '@queries/app/servers';
|
||||
import {getCurrentChannel} from '@queries/servers/channel';
|
||||
import {
|
||||
|
|
@ -45,7 +42,7 @@ import {getCurrentUser} from '@queries/servers/user';
|
|||
import {dismissAllModals, popToRoot} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug, logInfo} from '@utils/log';
|
||||
import {logInfo} from '@utils/log';
|
||||
|
||||
import {handleCategoryCreatedEvent, handleCategoryDeletedEvent, handleCategoryOrderUpdatedEvent, handleCategoryUpdatedEvent} from './category';
|
||||
import {handleChannelConvertedEvent, handleChannelCreatedEvent,
|
||||
|
|
@ -116,13 +113,22 @@ export async function handleClose(serverUrl: string, lastDisconnect: number) {
|
|||
});
|
||||
}
|
||||
|
||||
async function doReconnectRest(serverUrl: string, operator: ServerDataOperator, currentTeamId: string, currentUserId: string, config: ClientConfig, license: ClientLicense, lastDisconnectedAt: number) {
|
||||
async function doReconnect(serverUrl: string) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return;
|
||||
}
|
||||
|
||||
const appDatabase = DatabaseManager.appDatabase?.database;
|
||||
if (!appDatabase) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {database} = operator;
|
||||
|
||||
const lastDisconnectedAt = await getWebSocketLastDisconnected(database);
|
||||
resetWebSocketLastDisconnected(operator);
|
||||
|
||||
const currentTeam = await getCurrentTeam(database);
|
||||
const currentChannel = await getCurrentChannel(database);
|
||||
const currentActiveServerUrl = await getActiveServerUrl(DatabaseManager.appDatabase!.database);
|
||||
|
|
@ -170,51 +176,15 @@ async function doReconnectRest(serverUrl: string, operator: ServerDataOperator,
|
|||
await operator.batchRecords(models);
|
||||
logInfo('WEBSOCKET RECONNECT MODELS BATCHING TOOK', `${Date.now() - dt}ms`);
|
||||
|
||||
const {locale: currentUserLocale} = (await getCurrentUser(database))!;
|
||||
const {id: currentUserId, locale: currentUserLocale} = (await getCurrentUser(database))!;
|
||||
const {config, license} = await getCommonSystemValues(database);
|
||||
await deferredAppEntryActions(serverUrl, lastDisconnectedAt, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, initialTeamId, switchedToChannel ? initialChannelId : undefined);
|
||||
|
||||
// https://mattermost.atlassian.net/browse/MM-41520
|
||||
}
|
||||
|
||||
async function doReconnect(serverUrl: string) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {database} = operator;
|
||||
const system = await getCommonSystemValues(database);
|
||||
const lastDisconnectedAt = await getWebSocketLastDisconnected(database);
|
||||
|
||||
resetWebSocketLastDisconnected(operator);
|
||||
let {config, license} = await fetchConfigAndLicense(serverUrl);
|
||||
if (!config) {
|
||||
config = system.config;
|
||||
}
|
||||
|
||||
if (!license) {
|
||||
license = system.license;
|
||||
}
|
||||
|
||||
const currentActiveServerUrl = await getActiveServerUrl(DatabaseManager.appDatabase!.database);
|
||||
if (serverUrl === currentActiveServerUrl) {
|
||||
DeviceEventEmitter.emit(Events.FETCHING_POSTS, true);
|
||||
}
|
||||
|
||||
if (config.FeatureFlagGraphQL === 'true') {
|
||||
const {error} = await graphQLCommon(serverUrl, true, system.currentTeamId, system.currentChannelId);
|
||||
if (error) {
|
||||
logDebug('Error using GraphQL, trying REST', error);
|
||||
await doReconnectRest(serverUrl, operator, system.currentTeamId, system.currentUserId, config, license, lastDisconnectedAt);
|
||||
}
|
||||
} else {
|
||||
await doReconnectRest(serverUrl, operator, system.currentTeamId, system.currentUserId, config, license, lastDisconnectedAt);
|
||||
}
|
||||
|
||||
// Calls is not set up for GraphQL yet
|
||||
if (isSupportedServerCalls(config?.Version)) {
|
||||
loadConfigAndCalls(serverUrl, system.currentUserId);
|
||||
loadConfigAndCalls(serverUrl, currentUserId);
|
||||
}
|
||||
|
||||
// https://mattermost.atlassian.net/browse/MM-41520
|
||||
}
|
||||
|
||||
export async function handleEvent(serverUrl: string, msg: WebSocketMessage) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import {Client} from '@client/rest';
|
||||
import {MEMBERS_PER_PAGE} from '@constants/graphql';
|
||||
import NetworkManager from '@managers/network_manager';
|
||||
|
||||
import {Client} from '../rest';
|
||||
|
||||
import QueryNames from './constants';
|
||||
|
||||
const doGQLQuery = async (serverUrl: string, query: string, variables: {[name: string]: any}, operationName: string) => {
|
||||
|
|
@ -321,6 +320,11 @@ query ${QueryNames.QUERY_ALL_CHANNELS}($perPage: Int!){
|
|||
schemeAdmin
|
||||
lastViewedAt
|
||||
notifyProps
|
||||
roles {
|
||||
id
|
||||
name
|
||||
permissions
|
||||
}
|
||||
channel {
|
||||
id
|
||||
header
|
||||
|
|
@ -358,6 +362,11 @@ query ${QueryNames.QUERY_ALL_CHANNELS_NEXT}($perPage: Int!, $cursor: String!) {
|
|||
schemeAdmin
|
||||
lastViewedAt
|
||||
notifyProps
|
||||
roles {
|
||||
id
|
||||
name
|
||||
permissions
|
||||
}
|
||||
channel {
|
||||
id
|
||||
header
|
||||
|
|
|
|||
Loading…
Reference in a new issue