From 8a8a8884202c46babc32c53045197f8197f5f3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Fri, 9 Dec 2022 20:08:45 +0100 Subject: [PATCH] Fix issues when removing a user from a team (#6855) --- app/actions/remote/channel.ts | 9 +++-- app/actions/remote/team.ts | 7 ++-- app/actions/websocket/channel.ts | 40 +++---------------- .../team_list/team_item/team_item.tsx | 6 ++- app/queries/servers/channel.ts | 18 ++++++--- app/queries/servers/team.ts | 18 ++++++--- 6 files changed, 43 insertions(+), 55 deletions(-) diff --git a/app/actions/remote/channel.ts b/app/actions/remote/channel.ts index e9c43e18d..8d8085da0 100644 --- a/app/actions/remote/channel.ts +++ b/app/actions/remote/channel.ts @@ -20,7 +20,7 @@ import {getActiveServer} from '@queries/app/servers'; import {prepareMyChannelsForTeam, getChannelById, getChannelByName, getMyChannel, getChannelInfo, queryMyChannelSettingsByIds, getMembersCountByChannelsId} from '@queries/servers/channel'; import {queryPreferencesByCategoryAndName} from '@queries/servers/preference'; import {getCommonSystemValues, getConfig, getCurrentChannelId, getCurrentTeamId, getCurrentUserId, getLicense, setCurrentChannelId, setCurrentTeamAndChannelId} from '@queries/servers/system'; -import {getNthLastChannelFromTeam, getMyTeamById, getTeamByName, queryMyTeams} from '@queries/servers/team'; +import {getNthLastChannelFromTeam, getMyTeamById, getTeamByName, queryMyTeams, removeChannelFromTeamHistory} from '@queries/servers/team'; import {getCurrentUser} from '@queries/servers/user'; import {dismissAllModals, popToRoot} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; @@ -1302,7 +1302,7 @@ export const convertChannelToPrivate = async (serverUrl: string, channelId: stri } }; -export const handleKickFromChannel = async (serverUrl: string, channelId: string) => { +export const handleKickFromChannel = async (serverUrl: string, channelId: string, event: string = Events.LEAVE_CHANNEL) => { try { const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); @@ -1314,7 +1314,7 @@ export const handleKickFromChannel = async (serverUrl: string, channelId: string const currentServer = await getActiveServer(); if (currentServer?.url === serverUrl) { const channel = await getChannelById(database, channelId); - DeviceEventEmitter.emit(Events.LEAVE_CHANNEL, channel?.displayName); + DeviceEventEmitter.emit(event, channel?.displayName); await dismissAllModals(); await popToRoot(); } @@ -1323,7 +1323,8 @@ export const handleKickFromChannel = async (serverUrl: string, channelId: string if (tabletDevice) { const teamId = await getCurrentTeamId(database); - const newChannelId = await getNthLastChannelFromTeam(database, teamId); + await removeChannelFromTeamHistory(operator, teamId, channelId); + const newChannelId = await getNthLastChannelFromTeam(database, teamId, 0, channelId); if (newChannelId) { if (currentServer?.url === serverUrl) { if (newChannelId === Screens.GLOBAL_THREADS) { diff --git a/app/actions/remote/team.ts b/app/actions/remote/team.ts index e633cedd4..a00a83b09 100644 --- a/app/actions/remote/team.ts +++ b/app/actions/remote/team.ts @@ -12,7 +12,7 @@ import {getActiveServerUrl} from '@queries/app/servers'; import {prepareCategoriesAndCategoriesChannels} from '@queries/servers/categories'; import {prepareMyChannelsForTeam, getDefaultChannelForTeam} from '@queries/servers/channel'; import {prepareCommonSystemValues, getCurrentTeamId, getCurrentUserId} from '@queries/servers/system'; -import {addTeamToTeamHistory, prepareDeleteTeam, prepareMyTeams, getNthLastChannelFromTeam, queryTeamsById, syncTeamTable, getLastTeam, getTeamById} from '@queries/servers/team'; +import {addTeamToTeamHistory, prepareDeleteTeam, prepareMyTeams, getNthLastChannelFromTeam, queryTeamsById, syncTeamTable, getLastTeam, getTeamById, removeTeamFromTeamHistory} from '@queries/servers/team'; import {dismissAllModals, popToRoot, resetToTeams} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {isTablet} from '@utils/helpers'; @@ -330,7 +330,7 @@ export async function handleTeamChange(serverUrl: string, teamId: string) { export async function handleKickFromTeam(serverUrl: string, teamId: string) { try { - const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); const currentTeamId = await getCurrentTeamId(database); if (currentTeamId !== teamId) { return; @@ -344,7 +344,8 @@ export async function handleKickFromTeam(serverUrl: string, teamId: string) { await popToRoot(); } - const teamToJumpTo = await getLastTeam(database); + await removeTeamFromTeamHistory(operator, teamId); + const teamToJumpTo = await getLastTeam(database, teamId); if (teamToJumpTo) { await handleTeamChange(serverUrl, teamToJumpTo); } else if (currentServer === serverUrl) { diff --git a/app/actions/websocket/channel.ts b/app/actions/websocket/channel.ts index 5b883ecbc..e765f17e0 100644 --- a/app/actions/websocket/channel.ts +++ b/app/actions/websocket/channel.ts @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import {Model} from '@nozbe/watermelondb'; -import {DeviceEventEmitter} from 'react-native'; import {addChannelToDefaultCategory} from '@actions/local/category'; import { @@ -10,22 +9,17 @@ import { storeMyChannelsForTeam, updateChannelInfoFromChannel, updateMyChannelFromWebsocket, } from '@actions/local/channel'; import {storePostsForChannel} from '@actions/local/post'; -import {switchToGlobalThreads} from '@actions/local/thread'; -import {fetchMissingDirectChannelsInfo, fetchMyChannel, fetchChannelStats, fetchChannelById, switchToChannelById, handleKickFromChannel} from '@actions/remote/channel'; +import {fetchMissingDirectChannelsInfo, fetchMyChannel, fetchChannelStats, fetchChannelById, handleKickFromChannel} from '@actions/remote/channel'; import {fetchPostsForChannel} from '@actions/remote/post'; import {fetchRolesIfNeeded} from '@actions/remote/role'; import {fetchUsersByIds, updateUsersNoLongerVisible} from '@actions/remote/user'; import {loadCallForChannel} from '@calls/actions/calls'; -import {Events, Screens} from '@constants'; +import {Events} from '@constants'; import DatabaseManager from '@database/manager'; -import {getActiveServer} from '@queries/app/servers'; import {deleteChannelMembership, getChannelById, prepareMyChannelsForTeam, getCurrentChannel} from '@queries/servers/channel'; -import {getConfig, setCurrentChannelId, getCurrentChannelId, getCurrentTeamId} from '@queries/servers/system'; -import {getNthLastChannelFromTeam} from '@queries/servers/team'; +import {getConfig, getCurrentChannelId} from '@queries/servers/system'; import {getCurrentUser, getTeammateNameDisplay, getUserById} from '@queries/servers/user'; -import {dismissAllModals, popToRoot} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; -import {isTablet} from '@utils/helpers'; import {logDebug} from '@utils/log'; // Received when current user created a channel in a different client @@ -396,34 +390,10 @@ export async function handleChannelDeletedEvent(serverUrl: string, msg: WebSocke } if (config?.ExperimentalViewArchivedChannels !== 'true') { - await removeCurrentUserFromChannel(serverUrl, channelId); - if (currentChannel && currentChannel.id === channelId) { - const currentServer = await getActiveServer(); - - if (currentServer?.url === serverUrl) { - DeviceEventEmitter.emit(Events.CHANNEL_ARCHIVED, currentChannel.displayName); - await dismissAllModals(); - await popToRoot(); - - if (await isTablet()) { - let tId = currentChannel.teamId; - if (!tId) { - tId = await getCurrentTeamId(database); - } - const channelToJumpTo = await getNthLastChannelFromTeam(database, tId); - if (channelToJumpTo) { - if (channelToJumpTo === Screens.GLOBAL_THREADS) { - switchToGlobalThreads(serverUrl, tId); - return; - } - switchToChannelById(serverUrl, channelToJumpTo, tId); - } // TODO else jump to "join a channel" screen - } else { - setCurrentChannelId(operator, ''); - } - } + await handleKickFromChannel(serverUrl, channelId, Events.CHANNEL_ARCHIVED); } + await removeCurrentUserFromChannel(serverUrl, channelId); } } catch { // Do nothing diff --git a/app/components/team_sidebar/team_list/team_item/team_item.tsx b/app/components/team_sidebar/team_list/team_item/team_item.tsx index 031fe5d39..c3a204b26 100644 --- a/app/components/team_sidebar/team_list/team_item/team_item.tsx +++ b/app/components/team_sidebar/team_list/team_item/team_item.tsx @@ -16,7 +16,7 @@ import TeamIcon from './team_icon'; import type TeamModel from '@typings/database/models/servers/team'; type Props = { - team: TeamModel; + team?: TeamModel; hasUnreads: boolean; mentionCount: number; selected: boolean; @@ -62,6 +62,10 @@ export default function TeamItem({team, hasUnreads, mentionCount, selected}: Pro const styles = getStyleSheet(theme); const serverUrl = useServerUrl(); + if (!team) { + return null; + } + const hasBadge = Boolean(mentionCount || hasUnreads); let badgeStyle = styles.unread; let value = mentionCount; diff --git a/app/queries/servers/channel.ts b/app/queries/servers/channel.ts index 25666bfd7..a10f5e689 100644 --- a/app/queries/servers/channel.ts +++ b/app/queries/servers/channel.ts @@ -245,7 +245,7 @@ export const getChannelInfo = async (database: Database, channelId: string) => { } }; -export const getDefaultChannelForTeam = async (database: Database, teamId: string) => { +export const getDefaultChannelForTeam = async (database: Database, teamId: string, ignoreId?: string) => { let channel: ChannelModel|undefined; let canIJoinPublicChannelsInTeam = false; const roles = await queryRoles(database).fetch(); @@ -254,13 +254,19 @@ export const getDefaultChannelForTeam = async (database: Database, teamId: strin canIJoinPublicChannelsInTeam = hasPermission(roles, Permissions.JOIN_PUBLIC_CHANNELS); } + const clauses = [ + Q.where('team_id', teamId), + Q.where('delete_at', Q.eq(0)), + Q.where('type', General.OPEN_CHANNEL), + ]; + + if (ignoreId) { + clauses.push(Q.where('channel_id', Q.notEq(ignoreId))); + } + const myChannels = await database.get(CHANNEL).query( Q.on(MY_CHANNEL, 'id', Q.notEq('')), - Q.and( - Q.where('team_id', teamId), - Q.where('delete_at', 0), - Q.where('type', General.OPEN_CHANNEL), - ), + Q.and(...clauses), Q.sortBy('display_name', Q.asc), ).fetch(); diff --git a/app/queries/servers/team.ts b/app/queries/servers/team.ts index 2e57c3917..4f00b776b 100644 --- a/app/queries/servers/team.ts +++ b/app/queries/servers/team.ts @@ -84,7 +84,7 @@ export const getTeamChannelHistory = async (database: Database, teamId: string) } }; -export const getNthLastChannelFromTeam = async (database: Database, teamId: string, n = 0) => { +export const getNthLastChannelFromTeam = async (database: Database, teamId: string, n = 0, ignoreIdForDefault?: string) => { let channelId = ''; try { @@ -98,7 +98,7 @@ export const getNthLastChannelFromTeam = async (database: Database, teamId: stri if (!channelId) { // No channel history for the team - const channel = await getDefaultChannelForTeam(database, teamId); + const channel = await getDefaultChannelForTeam(database, teamId, ignoreIdForDefault); if (channel) { channelId = channel.id; } @@ -156,13 +156,13 @@ export const removeTeamFromTeamHistory = async (operator: ServerDataOperator, te return patchTeamHistory(operator, teamIds, prepareRecordsOnly); }; -export const getLastTeam = async (database: Database) => { +export const getLastTeam = async (database: Database, ignoreIdForDefault?: string) => { const teamHistory = (await getTeamHistory(database)); if (teamHistory.length > 0) { return teamHistory[0]; } - return getDefaultTeamId(database); + return getDefaultTeamId(database, ignoreIdForDefault); }; export async function syncTeamTable(operator: ServerDataOperator, teams: Team[]) { @@ -190,7 +190,7 @@ export async function syncTeamTable(operator: ServerDataOperator, teams: Team[]) } } -export const getDefaultTeamId = async (database: Database) => { +export const getDefaultTeamId = async (database: Database, ignoreId?: string) => { const user = await getCurrentUser(database); const config = await getConfig(database); const teamOrderPreferences = await queryPreferencesByCategoryAndName(database, Preferences.TEAMS_ORDER, '').fetch(); @@ -199,7 +199,13 @@ export const getDefaultTeamId = async (database: Database) => { teamOrderPreference = teamOrderPreferences[0].value; } - const teamModels = await database.get(TEAM).query(Q.on(MY_TEAM, Q.where('id', Q.notEq('')))).fetch(); + const clauses: Q.Clause[] = [Q.on(MY_TEAM, Q.where('id', Q.notEq('')))]; + + if (ignoreId) { + clauses.push(Q.where('id', Q.notEq(ignoreId))); + } + + const teamModels = await database.get(TEAM).query(...clauses).fetch(); const defaultTeam = selectDefaultTeam(teamModels, user?.locale || DEFAULT_LOCALE, teamOrderPreference, config?.ExperimentalPrimaryTeam); return defaultTeam?.id;