diff --git a/app/actions/remote/groups.ts b/app/actions/remote/groups.ts index 53d87ede2..62b054193 100644 --- a/app/actions/remote/groups.ts +++ b/app/actions/remote/groups.ts @@ -9,6 +9,21 @@ import {getTeamById} from '@queries/servers/team'; import {forceLogoutIfNecessary} from './session'; +export const fetchGroup = async (serverUrl: string, id: string, fetchOnly = false) => { + try { + const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + const client: Client = NetworkManager.getClient(serverUrl); + + const group = await client.getGroup(id); + + // Save locally + return operator.handleGroups({groups: [group], prepareRecordsOnly: fetchOnly}); + } catch (error) { + forceLogoutIfNecessary(serverUrl, error as ClientErrorProps); + return {error}; + } +}; + export const fetchGroupsForAutocomplete = async (serverUrl: string, query: string, fetchOnly = false) => { try { const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); diff --git a/app/actions/websocket/group.ts b/app/actions/websocket/group.ts new file mode 100644 index 000000000..9ebddae88 --- /dev/null +++ b/app/actions/websocket/group.ts @@ -0,0 +1,45 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {fetchGroup, fetchGroupsForChannel, fetchGroupsForMember, fetchGroupsForTeam} from '@actions/remote/groups'; +import DatabaseManager from '@database/manager'; +import {logError} from '@utils/log'; + +type WebsocketGroupMessage = WebSocketMessage<{ + group?: string; // type Group +}> + +const handleError = (serverUrl: string, e: unknown, msg: WebsocketGroupMessage) => { + logError(`Group WS: ${msg.event}`, e, msg); + + const {team_id, channel_id, user_id} = msg.broadcast; + + if (team_id) { + fetchGroupsForTeam(serverUrl, msg.broadcast.team_id); + } + if (channel_id) { + fetchGroupsForChannel(serverUrl, msg.broadcast.channel_id); + } + if (user_id) { + fetchGroupsForMember(serverUrl, msg.broadcast.user_id); + } + + const group = JSON.parse(msg.data.group || '') as Partial; + if (!team_id && !channel_id && !user_id && group.id) { + fetchGroup(serverUrl, group.id); + } +}; + +export async function handleGroupReceivedEvent(serverUrl: string, msg: WebsocketGroupMessage) { + let group: Group; + + try { + if (msg?.data?.group) { + const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + group = JSON.parse(msg.data.group); + operator.handleGroups({groups: [group], prepareRecordsOnly: false}); + } + } catch (e) { + handleError(serverUrl, e, msg); + } +} diff --git a/app/actions/websocket/index.ts b/app/actions/websocket/index.ts index 01bbce1da..64e6c353c 100644 --- a/app/actions/websocket/index.ts +++ b/app/actions/websocket/index.ts @@ -49,6 +49,7 @@ import {handleChannelConvertedEvent, handleChannelCreatedEvent, handleDirectAddedEvent, handleUserAddedToChannelEvent, handleUserRemovedFromChannelEvent} from './channel'; +import {handleGroupReceivedEvent} from './group'; import {handleOpenDialogEvent} from './integrations'; import {handleNewPostEvent, handlePostDeleted, handlePostEdited, handlePostUnread} from './posts'; import {handlePreferenceChangedEvent, handlePreferencesChangedEvent, handlePreferencesDeletedEvent} from './preferences'; @@ -401,5 +402,9 @@ export async function handleEvent(serverUrl: string, msg: WebSocketMessage) { case WebsocketEvents.CALLS_USER_UNRAISE_HAND: handleCallUserUnraiseHand(serverUrl, msg); break; + + case WebsocketEvents.GROUP_RECEIVED: + handleGroupReceivedEvent(serverUrl, msg); + break; } } diff --git a/app/client/rest/groups.ts b/app/client/rest/groups.ts index 9cedf521f..7b9829199 100644 --- a/app/client/rest/groups.ts +++ b/app/client/rest/groups.ts @@ -6,6 +6,7 @@ import {buildQueryString} from '@utils/helpers'; import {PER_PAGE_DEFAULT} from './constants'; export interface ClientGroupsMix { + getGroup: (id: string) => Promise; getGroups: (params: {query?: string; filterAllowReference?: boolean; page?: number; perPage?: number; since?: number; includeMemberCount?: boolean}) => Promise; getAllGroupsAssociatedToChannel: (channelId: string, filterAllowReference?: boolean) => Promise<{groups: Group[]; total_group_count: number}>; getAllGroupsAssociatedToMembership: (userId: string, filterAllowReference?: boolean) => Promise; @@ -16,6 +17,13 @@ export interface ClientGroupsMix { } const ClientGroups = (superclass: any) => class extends superclass { + getGroup = async (id: string) => { + return this.doFetch( + `${this.urlVersion}/groups/${id}`, + {method: 'get'}, + ); + }; + getGroups = async ({query = '', filterAllowReference = true, page = 0, perPage = PER_PAGE_DEFAULT, since = 0, includeMemberCount = false}) => { return this.doFetch( `${this.urlVersion}/groups${buildQueryString({ diff --git a/app/constants/websocket.ts b/app/constants/websocket.ts index 50b639078..7c9a56d21 100644 --- a/app/constants/websocket.ts +++ b/app/constants/websocket.ts @@ -66,5 +66,8 @@ const WebsocketEvents = { CALLS_SCREEN_OFF: `custom_${Calls.PluginId}_user_screen_off`, CALLS_USER_RAISE_HAND: `custom_${Calls.PluginId}_user_raise_hand`, CALLS_USER_UNRAISE_HAND: `custom_${Calls.PluginId}_user_unraise_hand`, + GROUP_RECEIVED: 'received_group', + GROUP_MEMBER_ADD: 'group_member_add', + GROUP_MEMBER_DELETE: 'group_member_delete', }; export default WebsocketEvents;