diff --git a/app/actions/websocket/channel.ts b/app/actions/websocket/channel.ts index f74ae749f2..c0007d5cb1 100644 --- a/app/actions/websocket/channel.ts +++ b/app/actions/websocket/channel.ts @@ -24,7 +24,8 @@ export async function handleUserAddedToChannelEvent(serverUrl: string, msg: any) return; } const currentUser = await queryCurrentUser(database.database); - const {team_id: teamId, channel_id: channelId, user_id: userId} = msg.data; + const {team_id: teamId, user_id: userId} = msg.data; + const {channel_id: channelId} = msg.broadcast; const models: Model[] = []; try { @@ -64,8 +65,6 @@ export async function handleUserAddedToChannelEvent(serverUrl: string, msg: any) if (authors?.length) { models.push(...await database.operator.handleUsers({users: authors, prepareRecordsOnly: true})); } - - database.operator.batchRecords(models); } else { const channels = await queryChannelsById(database.database, [channelId]); if (channels?.[0]) { @@ -94,8 +93,9 @@ export async function handleUserRemovedFromChannelEvent(serverUrl: string, msg: return; } - const userId = msg.data.user_id; - const channelId = msg.data.channel_id; + // Depending on who was removed, the ids may come from one place dataset or the other. + const userId = msg.data.user_id || msg.broadcast.user_id; + const channelId = msg.data.channel_id || msg.broadcast.channel_id; const models: Model[] = []; @@ -158,18 +158,20 @@ export async function handleChannelDeletedEvent(serverUrl: string, msg: WebSocke return; } + const {channel_id: channelId, delete_at: deleteAt} = msg.data; + const config = await queryConfig(database.database); - await setChannelDeleteAt(serverUrl, msg.data.channel_id, msg.data.delete_at); + await setChannelDeleteAt(serverUrl, channelId, deleteAt); if (user.isGuest) { updateUsersNoLongerVisible(serverUrl); } if (config?.ExperimentalViewArchivedChannels !== 'true') { - removeCurrentUserFromChannel(serverUrl, msg.data.channel_id); + removeCurrentUserFromChannel(serverUrl, channelId); - if (currentChannel && currentChannel.id === msg.data.channel_id) { + if (currentChannel && currentChannel.id === channelId) { const currentServer = await queryActiveServer(DatabaseManager.appDatabase!.database); if (currentServer?.url === serverUrl) { diff --git a/app/actions/websocket/posts.ts b/app/actions/websocket/posts.ts index 2c4352aa24..a4d351dd6a 100644 --- a/app/actions/websocket/posts.ts +++ b/app/actions/websocket/posts.ts @@ -213,9 +213,11 @@ export function handlePostDeleted(serverUrl: string, msg: WebSocketMessage) { } export async function handlePostUnread(serverUrl: string, msg: WebSocketMessage) { - const {channels} = await fetchMyChannel(serverUrl, msg.broadcast.team_id, msg.broadcast.channel_id, true); + const {team_id: teamId, channel_id: channelId} = msg.broadcast; + const {mention_count: mentionCount, msg_count: msgCount, last_viewed_at: lastViewedAt} = msg.data; + const {channels} = await fetchMyChannel(serverUrl, teamId, channelId, true); const channel = channels?.[0]; const postNumber = channel?.total_msg_count; - const delta = postNumber ? postNumber - msg.data.msg_count : msg.data.msg_count; - markChannelAsUnread(serverUrl, msg.broadcast.channel_id, delta, msg.data.mention_count, msg.data.last_viewed_at); + const delta = postNumber ? postNumber - msgCount : msgCount; + markChannelAsUnread(serverUrl, channelId, delta, mentionCount, lastViewedAt); } diff --git a/app/actions/websocket/teams.ts b/app/actions/websocket/teams.ts index 2231a59109..9aefd7d35a 100644 --- a/app/actions/websocket/teams.ts +++ b/app/actions/websocket/teams.ts @@ -28,15 +28,16 @@ export async function handleLeaveTeamEvent(serverUrl: string, msg: WebSocketMess return; } - if (user.id === msg.data.user_id) { - await removeUserFromTeam(serverUrl, msg.data.team_id); + const {user_id: userId, team_id: teamId} = msg.data; + if (user.id === userId) { + await removeUserFromTeam(serverUrl, teamId); fetchAllTeams(serverUrl); if (user.isGuest) { updateUsersNoLongerVisible(serverUrl); } - if (currentTeamId === msg.data.team_id) { + if (currentTeamId === teamId) { const currentServer = await queryActiveServer(DatabaseManager.appDatabase!.database); if (currentServer?.url === serverUrl) { @@ -70,13 +71,26 @@ export async function handleUpdateTeamEvent(serverUrl: string, msg: WebSocketMes } } +// As of today, the server sends a duplicated event to add the user to the team. +// If we do not handle this, this ends up showing some errors in the database, apart +// of the extra computation time. We use this to track the events that are being handled +// and make sure we only handle one. +const addingTeam: {[id: string]: boolean} = {}; + export async function handleUserAddedToTeamEvent(serverUrl: string, msg: WebSocketMessage) { const database = DatabaseManager.serverDatabases[serverUrl]; if (!database) { return; } + const {team_id: teamId} = msg.data; - const {teams, memberships: teamMemberships} = await fetchMyTeam(serverUrl, msg.data.team_id, true); + // Ignore duplicated team join events sent by the server + if (addingTeam[teamId]) { + return; + } + addingTeam[teamId] = true; + + const {teams, memberships: teamMemberships} = await fetchMyTeam(serverUrl, teamId, true); const modelPromises: Array> = []; if (teams?.length && teamMemberships?.length) { @@ -108,4 +122,6 @@ export async function handleUserAddedToTeamEvent(serverUrl: string, msg: WebSock const models = await Promise.all(modelPromises); await database.operator.batchRecords(models.flat()); } + + delete addingTeam[teamId]; } diff --git a/app/queries/servers/categories.ts b/app/queries/servers/categories.ts index 775269f471..3cad2d35c4 100644 --- a/app/queries/servers/categories.ts +++ b/app/queries/servers/categories.ts @@ -117,13 +117,13 @@ export const prepareCategoryChannels = ( export const prepareDeleteCategory = async (category: CategoryModel): Promise => { const preparedModels: Model[] = [category.prepareDestroyPermanently()]; - const associatedChildren: Array> = [ + const associatedChildren: Array|undefined> = [ category.categoryChannels, ]; - for await (const children of associatedChildren) { - const models = await children?.fetch?.() as Model[] | undefined; + await Promise.all(associatedChildren.map(async (children) => { + const models = await children?.fetch(); models?.forEach((model) => preparedModels.push(model.prepareDestroyPermanently())); - } + })); return preparedModels; }; diff --git a/app/queries/servers/channel.ts b/app/queries/servers/channel.ts index ffc9d29b6a..48a9c03088 100644 --- a/app/queries/servers/channel.ts +++ b/app/queries/servers/channel.ts @@ -15,7 +15,6 @@ import type ServerDataOperator from '@database/operator/server_data_operator'; import type ChannelModel from '@typings/database/models/servers/channel'; import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; -import type PostModel from '@typings/database/models/servers/post'; const {SERVER: {CHANNEL, MY_CHANNEL, CHANNEL_MEMBERSHIP}} = MM_TABLES; @@ -96,29 +95,29 @@ export const prepareMyChannelsForTeam = async (operator: ServerDataOperator, tea export const prepareDeleteChannel = async (channel: ChannelModel): Promise => { const preparedModels: Model[] = [channel.prepareDestroyPermanently()]; - const relations: Array> = [channel.membership, channel.info, channel.settings, channel.categoryChannel]; - for await (const relation of relations) { + const relations: Array | undefined> = [channel.membership, channel.info, channel.settings, channel.categoryChannel]; + await Promise.all(relations.map(async (relation) => { try { - const model = await relation?.fetch?.(); + const model = await relation?.fetch(); if (model) { preparedModels.push(model.prepareDestroyPermanently()); } } catch { // Record not found, do nothing } - } + })); - const associatedChildren: Array> = [ + const associatedChildren: Array | undefined> = [ channel.members, channel.drafts, channel.postsInChannel, ]; - for await (const children of associatedChildren) { - const models = await children?.fetch?.() as Model[] | undefined; + await Promise.all(associatedChildren.map(async (children) => { + const models = await children?.fetch(); models?.forEach((model) => preparedModels.push(model.prepareDestroyPermanently())); - } + })); - const posts = await channel.posts?.fetch?.() as PostModel[] | undefined; + const posts = await channel.posts?.fetch(); if (posts?.length) { for await (const post of posts) { const preparedPost = await prepareDeletePost(post); diff --git a/app/queries/servers/post.ts b/app/queries/servers/post.ts index 7a5782a962..580c255c01 100644 --- a/app/queries/servers/post.ts +++ b/app/queries/servers/post.ts @@ -29,11 +29,11 @@ export const prepareDeletePost = async (post: PostModel): Promise => { } } - const associatedChildren: Array> = [post.files, post.reactions]; - for await (const children of associatedChildren) { - const models = await children.fetch?.() as Model[] | undefined; + const associatedChildren: Array|undefined> = [post.files, post.reactions]; + await Promise.all(associatedChildren.map(async (children) => { + const models = await children?.fetch(); models?.forEach((model) => preparedModels.push(model.prepareDestroyPermanently())); - } + })); return preparedModels; }; diff --git a/app/queries/servers/team.ts b/app/queries/servers/team.ts index 2a266e82d1..08e8f50bc5 100644 --- a/app/queries/servers/team.ts +++ b/app/queries/servers/team.ts @@ -209,32 +209,32 @@ export const prepareDeleteTeam = async (team: TeamModel): Promise => { const preparedModels: Model[] = [team.prepareDestroyPermanently()]; const relations: Array> = [team.myTeam, team.teamChannelHistory]; - for await (const relation of relations) { + await Promise.all(relations.map(async (relation) => { try { - const model = await relation?.fetch?.(); + const model = await relation?.fetch(); if (model) { preparedModels.push(model.prepareDestroyPermanently()); } - } catch { + } catch (error) { // Record not found, do nothing } - } + })); - const associatedChildren: Array> = [ + const associatedChildren: Array|undefined> = [ team.members, team.slashCommands, team.teamSearchHistories, ]; - for await (const children of associatedChildren) { + await Promise.all(associatedChildren.map(async (children) => { try { - const models = await children.fetch?.() as Model[] | undefined; + const models = await children?.fetch(); models?.forEach((model) => preparedModels.push(model.prepareDestroyPermanently())); } catch { // Record not found, do nothing } - } + })); - const categories = await team.categories.fetch?.() as CategoryModel[] | undefined; + const categories = await team.categories?.fetch() as CategoryModel[] | undefined; if (categories?.length) { for await (const category of categories) { try { @@ -246,7 +246,7 @@ export const prepareDeleteTeam = async (team: TeamModel): Promise => { } } - const channels = await team.channels.fetch?.() as ChannelModel[] | undefined; + const channels = await team.channels?.fetch() as ChannelModel[] | undefined; if (channels?.length) { for await (const channel of channels) { try {