From d4d3971540dea939c0778bec43242db68ba58be1 Mon Sep 17 00:00:00 2001 From: Jason Frerich Date: Tue, 1 Feb 2022 06:14:49 -0600 Subject: [PATCH] [Gekidou MM-39726] - Websocket Events - Roles (#5859) --- app/actions/remote/role.ts | 1 - app/actions/websocket/index.ts | 15 ++-- app/actions/websocket/roles.ts | 122 +++++++++++++++++++++++++++++++++ app/constants/websocket.ts | 2 - app/queries/servers/role.ts | 18 +++-- 5 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 app/actions/websocket/roles.ts diff --git a/app/actions/remote/role.ts b/app/actions/remote/role.ts index 4ca243d69..37eac702b 100644 --- a/app/actions/remote/role.ts +++ b/app/actions/remote/role.ts @@ -42,7 +42,6 @@ export const fetchRolesIfNeeded = async (serverUrl: string, updatedRoles: string try { const roles = await client.getRolesByNames(newRoles); - if (!fetchOnly && roles.length) { await operator.handleRole({ roles, diff --git a/app/actions/websocket/index.ts b/app/actions/websocket/index.ts index 8e5f51a36..3715560ad 100644 --- a/app/actions/websocket/index.ts +++ b/app/actions/websocket/index.ts @@ -22,6 +22,7 @@ import {queryCurrentUser} from '@queries/servers/user'; import {handleChannelDeletedEvent, handleUserAddedToChannelEvent, handleUserRemovedFromChannelEvent} from './channel'; import {handleNewPostEvent, handlePostDeleted, handlePostEdited, handlePostUnread} from './posts'; import {handlePreferenceChangedEvent, handlePreferencesChangedEvent, handlePreferencesDeletedEvent} from './preferences'; +import {handleUserRoleUpdatedEvent, handleTeamMemberRoleUpdatedEvent, handleRoleUpdatedEvent} from './roles'; import {handleLeaveTeamEvent, handleUserAddedToTeamEvent, handleUpdateTeamEvent} from './teams'; import {handleUserUpdatedEvent} from './users'; @@ -186,26 +187,18 @@ export async function handleEvent(serverUrl: string, msg: WebSocketMessage) { case WebsocketEvents.USER_UPDATED: handleUserUpdatedEvent(serverUrl, msg); break; - case WebsocketEvents.ROLE_ADDED: - break; - - // return dispatch(handleRoleAddedEvent(msg)); - case WebsocketEvents.ROLE_REMOVED: - break; - - // return dispatch(handleRoleRemovedEvent(msg)); case WebsocketEvents.ROLE_UPDATED: + handleRoleUpdatedEvent(serverUrl, msg); break; - // return dispatch(handleRoleUpdatedEvent(msg)); case WebsocketEvents.USER_ROLE_UPDATED: + handleUserRoleUpdatedEvent(serverUrl, msg); break; - // return dispatch(handleUserRoleUpdated(msg)); case WebsocketEvents.MEMBERROLE_UPDATED: + handleTeamMemberRoleUpdatedEvent(serverUrl, msg); break; - // return dispatch(handleUpdateMemberRoleEvent(msg)); case WebsocketEvents.CHANNEL_CREATED: break; diff --git a/app/actions/websocket/roles.ts b/app/actions/websocket/roles.ts new file mode 100644 index 000000000..24d3b9ca7 --- /dev/null +++ b/app/actions/websocket/roles.ts @@ -0,0 +1,122 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {fetchRolesIfNeeded} from '@actions/remote/role'; +import DatabaseManager from '@database/manager'; +import {queryRoleById} from '@queries/servers/role'; +import {queryCurrentUserId} from '@queries/servers/system'; +import {queryCurrentUser} from '@queries/servers/user'; + +import type {Model} from '@nozbe/watermelondb'; + +export async function handleRoleUpdatedEvent(serverUrl: string, msg: WebSocketMessage): Promise { + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (!operator) { + return; + } + + // only update Role records that exist in the Role Table + try { + const role = JSON.parse(msg.data.role) as Role; + const dbRole = await queryRoleById(operator.database, role.id); + if (!dbRole) { + return; + } + + operator.handleRole({ + roles: [role], + prepareRecordsOnly: false, + }); + } catch { + // do nothing + } +} + +export async function handleUserRoleUpdatedEvent(serverUrl: string, msg: WebSocketMessage): Promise { + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (!operator) { + return; + } + + const currentUserId = await queryCurrentUserId(operator.database); + if (currentUserId !== msg.data.user_id) { + return; + } + + const models: Model[] = []; + + // update Role Table if needed + const rolesArray = msg.data.roles.split(' '); + const newRoles = await fetchRolesIfNeeded(serverUrl, rolesArray, true); + if (newRoles?.roles?.length) { + const preparedRoleModels = await operator.handleRole({ + roles: newRoles.roles!, + prepareRecordsOnly: true, + }); + + if (preparedRoleModels.length) { + models.push(...preparedRoleModels); + } + } + + // update User Table record + const user = await queryCurrentUser(operator.database); + if (user) { + user!.prepareUpdate((u) => { + u.roles = msg.data.roles; + }); + models.push(user); + } + + if (models?.length) { + await operator.batchRecords(models); + } +} + +export async function handleTeamMemberRoleUpdatedEvent(serverUrl: string, msg: WebSocketMessage): Promise { + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (!operator) { + return; + } + + try { + const member = JSON.parse(msg.data.member); + + const currentUserId = await queryCurrentUserId(operator.database); + if (currentUserId !== member.user_id) { + return; + } + + const models: Model[] = []; + + // update Role Table if needed + const rolesArray = member.roles.split(' '); + const newRoles = await fetchRolesIfNeeded(serverUrl, rolesArray, true); + if (newRoles?.roles?.length) { + const preparedRoleModels = await operator.handleRole({ + roles: newRoles.roles!, + prepareRecordsOnly: true, + }); + if (preparedRoleModels.length) { + models.push(...preparedRoleModels); + } + } + + // update MyTeam Table + const myTeams: MyTeam[] = [{id: member.team_id, roles: member.roles}]; + const myTeamRecords = await operator.handleMyTeam({ + prepareRecordsOnly: true, + myTeams, + }); + + if (myTeamRecords.length) { + models.push(...myTeamRecords); + } + + if (models?.length) { + await operator.batchRecords(models); + } + } catch { + // do nothing + } +} diff --git a/app/constants/websocket.ts b/app/constants/websocket.ts index d3944294a..f56425b9b 100644 --- a/app/constants/websocket.ts +++ b/app/constants/websocket.ts @@ -21,8 +21,6 @@ const WebsocketEvents = { USER_REMOVED: 'user_removed', USER_UPDATED: 'user_updated', USER_ROLE_UPDATED: 'user_role_updated', - ROLE_ADDED: 'role_added', - ROLE_REMOVED: 'role_removed', ROLE_UPDATED: 'role_updated', TYPING: 'typing', STOP_TYPING: 'stop_typing', diff --git a/app/queries/servers/role.ts b/app/queries/servers/role.ts index 025bde96b..b6ab08dc2 100644 --- a/app/queries/servers/role.ts +++ b/app/queries/servers/role.ts @@ -3,12 +3,22 @@ import {Database} from '@nozbe/watermelondb'; -import {MM_TABLES} from '@constants/database'; -import Role from '@typings/database/models/servers/role'; +import {Database as DatabaseConstants} from '@constants'; -const {SERVER: {ROLE}} = MM_TABLES; +import type RoleModel from '@typings/database/models/servers/role'; + +const {ROLE} = DatabaseConstants.MM_TABLES.SERVER; export const queryRoles = async (database: Database) => { - const roles = await database.collections.get(ROLE).query().fetch() as Role[]; + const roles = await database.collections.get(ROLE).query().fetch(); return roles; }; + +export const queryRoleById = async (database: Database, roleId: string): Promise => { + try { + const role = (await database.get(ROLE).find(roleId)); + return role; + } catch { + return undefined; + } +};