Fix channel links when it implies joining a channel (#6686)

This commit is contained in:
Daniel Espino García 2022-10-18 16:16:06 +02:00 committed by GitHub
parent b086776c33
commit 4f4f96ff24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 159 deletions

View file

@ -17,10 +17,10 @@ import NetworkManager from '@managers/network_manager';
import {prepareMyChannelsForTeam, getChannelById, getChannelByName, getMyChannel, getChannelInfo, queryMyChannelSettingsByIds, getMembersCountByChannelsId} from '@queries/servers/channel';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {getCommonSystemValues, getConfig, getCurrentTeamId, getCurrentUserId, getLicense, setCurrentChannelId} from '@queries/servers/system';
import {prepareMyTeams, getNthLastChannelFromTeam, getMyTeamById, getTeamById, getTeamByName, queryMyTeams} from '@queries/servers/team';
import {getNthLastChannelFromTeam, getMyTeamById, getTeamByName, queryMyTeams} from '@queries/servers/team';
import {getCurrentUser} from '@queries/servers/user';
import EphemeralStore from '@store/ephemeral_store';
import {generateChannelNameFromDisplayName, getDirectChannelName, isArchived, isDMorGM} from '@utils/channel';
import {generateChannelNameFromDisplayName, getDirectChannelName, isDMorGM} from '@utils/channel';
import {isTablet} from '@utils/helpers';
import {logError, logInfo} from '@utils/log';
import {showMuteChannelSnackbar} from '@utils/snack_bar';
@ -32,14 +32,11 @@ import {fetchPostsForChannel} from './post';
import {setDirectChannelVisible} from './preference';
import {fetchRolesIfNeeded} from './role';
import {forceLogoutIfNecessary} from './session';
import {addUserToTeam, fetchTeamByName, removeUserFromTeam} from './team';
import {addCurrentUserToTeam, fetchTeamByName, removeCurrentUserFromTeam} from './team';
import {fetchProfilesInGroupChannels, fetchProfilesPerChannels, fetchUsersByIds, updateUsersNoLongerVisible} from './user';
import type {Client} from '@client/rest';
import type ChannelModel from '@typings/database/models/servers/channel';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
import type MyTeamModel from '@typings/database/models/servers/my_team';
import type TeamModel from '@typings/database/models/servers/team';
export type MyChannelsRequest = {
categories?: CategoryWithChannels[];
@ -531,11 +528,12 @@ export async function fetchDirectChannelsInfo(serverUrl: string, directChannels:
return fetchMissingDirectChannelsInfo(serverUrl, channels, currentUser?.locale, teammateDisplayNameSetting, currentUser?.id);
}
export async function joinChannel(serverUrl: string, userId: string, teamId: string, channelId?: string, channelName?: string, fetchOnly = false) {
export async function joinChannel(serverUrl: string, teamId: string, channelId?: string, channelName?: string, fetchOnly = false) {
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
if (!operator) {
return {error: `${serverUrl} database not found`};
}
const database = operator.database;
let client: Client;
try {
@ -544,6 +542,8 @@ export async function joinChannel(serverUrl: string, userId: string, teamId: str
return {error};
}
const userId = await getCurrentUserId(database);
let member: ChannelMembership | undefined;
let channel: Channel | undefined;
try {
@ -614,8 +614,7 @@ export async function joinChannelIfNeeded(serverUrl: string, channelId: string)
return {error: undefined};
}
const userId = await getCurrentUserId(database);
return joinChannel(serverUrl, userId, '', channelId);
return joinChannel(serverUrl, '', channelId);
} catch (error) {
return {error};
}
@ -634,167 +633,77 @@ export async function markChannelAsRead(serverUrl: string, channelId: string) {
export async function switchToChannelByName(serverUrl: string, channelName: string, teamName: string, errorHandler: (intl: IntlShape) => void, intl: IntlShape) {
let database;
let operator;
try {
const result = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
database = result.database;
operator = result.operator;
} catch (e) {
return {error: `${serverUrl} database not found`};
}
const onError = (joinedTeam: boolean, teamId?: string) => {
errorHandler(intl);
if (joinedTeam && teamId) {
removeCurrentUserFromTeam(serverUrl, teamId, false);
}
};
let joinedTeam = false;
let teamId = '';
try {
let myChannel: MyChannelModel | ChannelMembership | undefined;
let team: TeamModel | Team | undefined;
let myTeam: MyTeamModel | TeamMembership | undefined;
let name = teamName;
const roles: string [] = [];
const system = await getCommonSystemValues(database);
const currentTeam = await getTeamById(database, system.currentTeamId);
if (name === PERMALINK_GENERIC_TEAM_NAME_REDIRECT) {
name = currentTeam!.name;
if (teamName === PERMALINK_GENERIC_TEAM_NAME_REDIRECT) {
teamId = await getCurrentTeamId(database);
} else {
team = await getTeamByName(database, teamName);
}
const team = await getTeamByName(database, teamName);
const isTeamMember = team ? await getMyTeamById(database, team.id) : false;
teamId = team?.id || '';
if (!team) {
const fetchTeam = await fetchTeamByName(serverUrl, name, true);
if (fetchTeam.error) {
errorHandler(intl);
return {error: fetchTeam.error};
if (!isTeamMember) {
const fetchRequest = await fetchTeamByName(serverUrl, teamName);
if (!fetchRequest.team) {
onError(joinedTeam);
return {error: fetchRequest.error || 'no team received'};
}
const {error} = await addCurrentUserToTeam(serverUrl, fetchRequest.team.id);
if (error) {
onError(joinedTeam);
return {error};
}
teamId = fetchRequest.team.id;
joinedTeam = true;
}
team = fetchTeam.team!;
}
let joinedNewTeam = false;
myTeam = await getMyTeamById(database, team.id);
if (!myTeam) {
const added = await addUserToTeam(serverUrl, team.id, system.currentUserId, true);
if (added.error) {
errorHandler(intl);
return {error: added.error};
const channel = await getChannelByName(database, teamId, channelName);
const isChannelMember = channel ? await getMyChannel(database, channel.id) : false;
let channelId = channel?.id || '';
if (!isChannelMember) {
const fetchRequest = await fetchChannelByName(serverUrl, teamId, channelName, true);
if (!fetchRequest.channel) {
onError(joinedTeam, teamId);
return {error: fetchRequest.error || 'cannot fetch channel'};
}
myTeam = added.member!;
roles.push(...myTeam.roles.split(' '));
joinedNewTeam = true;
}
if (!myTeam) {
errorHandler(intl);
return {error: 'Could not fetch team member'};
}
let channel: Channel | ChannelModel | undefined = await getChannelByName(database, team.id, channelName);
if (!channel) {
const chReq = await fetchChannelByName(serverUrl, team.id, channelName, true);
if (chReq.error) {
errorHandler(intl);
return {error: chReq.error};
}
channel = chReq.channel;
}
if (!channel) {
errorHandler(intl);
return {error: 'Could not fetch channel'};
}
if (isArchived(channel) && system.config.ExperimentalViewArchivedChannels !== 'true') {
errorHandler(intl);
return {error: 'Channel is archived'};
}
myChannel = await getMyChannel(database, channel.id);
if (!myChannel) {
const channelTeamId = 'team_id' in channel ? channel.team_id : channel.teamId;
const req = await fetchMyChannel(serverUrl, channelTeamId || team.id, channel.id, true);
myChannel = req.memberships?.[0];
}
if (!myChannel) {
if (channel.type === General.PRIVATE_CHANNEL) {
const displayName = 'display_name' in channel ? channel.display_name : channel.displayName;
const {join} = await privateChannelJoinPrompt(displayName, intl);
if (fetchRequest.channel.type === General.PRIVATE_CHANNEL) {
const {join} = await privateChannelJoinPrompt(fetchRequest.channel.display_name, intl);
if (!join) {
if (joinedNewTeam) {
await removeUserFromTeam(serverUrl, team.id, system.currentUserId, true);
}
errorHandler(intl);
onError(joinedTeam, teamId);
return {error: 'Refused to join Private channel'};
}
logInfo('joining channel', displayName, channel.id);
const result = await joinChannel(serverUrl, system.currentUserId, team.id, channel.id, undefined, true);
if (result.error || !result.channel) {
if (joinedNewTeam) {
await removeUserFromTeam(serverUrl, team.id, system.currentUserId, true);
}
errorHandler(intl);
return {error: result.error};
}
myChannel = result.member!;
roles.push(...myChannel.roles.split(' '));
}
logInfo('joining channel', fetchRequest.channel.display_name, fetchRequest.channel.id);
const joinRequest = await joinChannel(serverUrl, teamId, undefined, channelName, false);
if (!joinRequest.channel) {
onError(joinedTeam, teamId);
return {error: joinRequest.error || 'no channel returned from join'};
}
channelId = fetchRequest.channel.id;
}
if (!myChannel) {
errorHandler(intl);
return {error: 'could not fetch channel member'};
}
const modelPromises: Array<Promise<Model[]>> = [];
if (!(team instanceof Model)) {
modelPromises.push(...prepareMyTeams(operator, [team], [(myTeam as TeamMembership)]));
} else if (!(myTeam instanceof Model)) {
const mt: MyTeam[] = [{
id: myTeam.team_id,
roles: myTeam.roles,
}];
modelPromises.push(
operator.handleMyTeam({myTeams: mt, prepareRecordsOnly: true}),
operator.handleTeamMemberships({teamMemberships: [myTeam], prepareRecordsOnly: true}),
);
}
// We are checking both, so this may become an issue
if (!(myChannel instanceof Model) && !(channel instanceof Model)) {
modelPromises.push(...await prepareMyChannelsForTeam(operator, team.id, [channel], [myChannel]));
}
let teamId;
if (team.id !== system.currentTeamId) {
teamId = team.id;
}
let channelId;
if (channel.id !== system.currentChannelId) {
channelId = channel.id;
}
if (modelPromises.length) {
const models = await Promise.all(modelPromises);
await operator.batchRecords(models.flat());
}
if (teamId) {
fetchMyChannelsForTeam(serverUrl, teamId, true, 0, false, true);
}
if (teamId || channelId) {
await switchToChannelById(serverUrl, channel.id, team.id);
}
if (roles.length) {
fetchRolesIfNeeded(serverUrl, roles);
}
switchToChannelById(serverUrl, channelId, teamId);
return {error: undefined};
} catch (error) {
errorHandler(intl);
onError(joinedTeam, teamId);
return {error};
}
}

View file

@ -55,6 +55,7 @@ export async function addUserToTeam(serverUrl: string, teamId: string, userId: s
try {
EphemeralStore.startAddingToTeam(teamId);
const team = await client.getTeam(teamId);
const member = await client.addToTeam(teamId, userId);
if (!fetchOnly) {
@ -68,6 +69,7 @@ export async function addUserToTeam(serverUrl: string, teamId: string, userId: s
}];
const models: Model[] = (await Promise.all([
operator.handleTeam({teams: [team], prepareRecordsOnly: true}),
operator.handleMyTeam({myTeams, prepareRecordsOnly: true}),
operator.handleTeamMemberships({teamMemberships: [member], prepareRecordsOnly: true}),
...await prepareMyChannelsForTeam(operator, teamId, channels || [], channelMembers || []),
@ -248,6 +250,16 @@ export async function fetchTeamByName(serverUrl: string, teamName: string, fetch
}
}
export const removeCurrentUserFromTeam = async (serverUrl: string, teamId: string, fetchOnly = false) => {
try {
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
const userId = await getCurrentUserId(database);
return removeUserFromTeam(serverUrl, teamId, userId, fetchOnly);
} catch (error) {
return {error};
}
};
export const removeUserFromTeam = async (serverUrl: string, teamId: string, userId: string, fetchOnly = false) => {
let client;
try {

View file

@ -21,7 +21,6 @@ type ChannelMentionProps = {
channelName: string;
channels: ChannelModel[];
currentTeamId: string;
currentUserId: string;
linkStyle: StyleProp<TextStyle>;
team: TeamModel;
textStyle: StyleProp<TextStyle>;
@ -57,7 +56,7 @@ function getChannelFromChannelName(name: string, channels: ChannelModel[], chann
}
const ChannelMention = ({
channelMentions, channelName, channels, currentTeamId, currentUserId,
channelMentions, channelName, channels, currentTeamId,
linkStyle, team, textStyle,
}: ChannelMentionProps) => {
const intl = useIntl();
@ -68,7 +67,7 @@ const ChannelMention = ({
let c = channel;
if (!c?.id && c?.display_name) {
const result = await joinChannel(serverUrl, currentUserId, currentTeamId, undefined, channelName);
const result = await joinChannel(serverUrl, currentTeamId, undefined, channelName);
if (result.error || !result.channel) {
const joinFailedMessage = {
id: t('mobile.join_channel.error'),

View file

@ -6,7 +6,7 @@ import withObservables from '@nozbe/with-observables';
import {switchMap} from 'rxjs/operators';
import {queryAllChannelsForTeam} from '@queries/servers/channel';
import {observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
import {observeCurrentTeamId} from '@queries/servers/system';
import {observeTeam} from '@queries/servers/team';
import ChannelMention from './channel_mention';
@ -17,7 +17,6 @@ export type ChannelMentions = Record<string, {id?: string; display_name: string;
const enhance = withObservables([], ({database}: WithDatabaseArgs) => {
const currentTeamId = observeCurrentTeamId(database);
const currentUserId = observeCurrentUserId(database);
const channels = currentTeamId.pipe(
switchMap((id) => queryAllChannelsForTeam(database, id).observeWithColumns(['display_name'])),
);
@ -28,7 +27,6 @@ const enhance = withObservables([], ({database}: WithDatabaseArgs) => {
return {
channels,
currentTeamId,
currentUserId,
team,
};
});

View file

@ -77,7 +77,6 @@ type Props = {
closeButton: ImageResource;
// Properties not changing during the lifetime of the screen)
currentUserId: string;
currentTeamId: string;
// Calculated Props
@ -102,7 +101,6 @@ export default function BrowseChannels(props: Props) {
canCreateChannels,
sharedChannelsEnabled,
closeButton,
currentUserId,
currentTeamId,
canShowArchivedChannels,
typeOfChannels,
@ -137,7 +135,7 @@ export default function BrowseChannels(props: Props) {
setHeaderButtons(false);
setAdding(true);
const result = await joinChannel(serverUrl, currentUserId, currentTeamId, channel.id, '', false);
const result = await joinChannel(serverUrl, currentTeamId, channel.id, '', false);
if (result.error) {
alertErrorWithFallback(

View file

@ -43,7 +43,6 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
return {
canCreateChannels,
currentUserId,
currentTeamId,
joinedChannels,
sharedChannelsEnabled,

View file

@ -279,7 +279,7 @@ function Permalink({
setLoading(true);
setError(undefined);
if (error?.teamId && error.channelId) {
const {error: joinError} = await joinChannel(serverUrl, currentUserId, error.teamId, error.channelId);
const {error: joinError} = await joinChannel(serverUrl, error.teamId, error.channelId);
if (joinError) {
Alert.alert('Error joining the channel', 'There was an error trying to join the channel');
setLoading(false);