[Gekidou] Manage user websocket events (#5862)
* Manage user websocket events * Revert ChannelMembership -> MyChannelMembership * Address feedback * Update channel display name when the user changes * Minor name and refactoring changes from feedback * Address feedback * Address feedback * Add line breaks for readability
This commit is contained in:
parent
55197b6125
commit
d5228633b2
14 changed files with 287 additions and 74 deletions
|
|
@ -1,25 +1,34 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Model} from '@nozbe/watermelondb';
|
||||
import {Model, Q} from '@nozbe/watermelondb';
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {Navigation as NavigationConstants, Screens} from '@constants';
|
||||
import {General, Navigation as NavigationConstants, Preferences, Screens} from '@constants';
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
import {prepareDeleteChannel, queryAllMyChannelIds, queryChannelsById, queryMyChannel} from '@queries/servers/channel';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {prepareCommonSystemValues, PrepareCommonSystemValuesArgs, queryCommonSystemValues, queryCurrentTeamId, setCurrentChannelId} from '@queries/servers/system';
|
||||
import {addChannelToTeamHistory, addTeamToTeamHistory, removeChannelFromTeamHistory} from '@queries/servers/team';
|
||||
import {queryCurrentUser} from '@queries/servers/user';
|
||||
import {dismissAllModalsAndPopToRoot, dismissAllModalsAndPopToScreen} from '@screens/navigation';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {displayGroupMessageName, displayUsername} from '@utils/user';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
export const switchToChannel = async (serverUrl: string, channelId: string, teamId?: string) => {
|
||||
const {SERVER: {CHANNEL_MEMBERSHIP, USER}} = MM_TABLES;
|
||||
|
||||
export const switchToChannel = async (serverUrl: string, channelId: string, teamId?: string, prepareRecordsOnly = false) => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
if (!database) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
const models: Model[] = [];
|
||||
try {
|
||||
const dt = Date.now();
|
||||
const isTabletDevice = await isTablet();
|
||||
|
|
@ -29,7 +38,6 @@ export const switchToChannel = async (serverUrl: string, channelId: string, team
|
|||
if (member) {
|
||||
const channel: ChannelModel = await member.channel.fetch();
|
||||
const {operator} = DatabaseManager.serverDatabases[serverUrl];
|
||||
const models = [];
|
||||
const commonValues: PrepareCommonSystemValuesArgs = {currentChannelId: channelId};
|
||||
if (isTabletDevice) {
|
||||
// On tablet, the channel is being rendered, by setting the channel to empty first we speed up
|
||||
|
|
@ -58,7 +66,7 @@ export const switchToChannel = async (serverUrl: string, channelId: string, team
|
|||
models.push(viewedAt);
|
||||
}
|
||||
|
||||
if (models.length) {
|
||||
if (models.length && !prepareRecordsOnly) {
|
||||
await operator.batchRecords(models);
|
||||
}
|
||||
|
||||
|
|
@ -75,21 +83,22 @@ export const switchToChannel = async (serverUrl: string, channelId: string, team
|
|||
return {error};
|
||||
}
|
||||
|
||||
return {error: undefined};
|
||||
return {models};
|
||||
};
|
||||
|
||||
export const localRemoveUserFromChannel = async (serverUrl: string, channelId: string) => {
|
||||
export const removeCurrentUserFromChannel = async (serverUrl: string, channelId: string, prepareRecordsOnly = false) => {
|
||||
const serverDatabase = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (!serverDatabase) {
|
||||
return;
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
const {operator, database} = serverDatabase;
|
||||
|
||||
const models: Model[] = [];
|
||||
const myChannel = await queryMyChannel(database, channelId);
|
||||
if (myChannel) {
|
||||
const channel = await myChannel.channel.fetch() as ChannelModel;
|
||||
const models = await prepareDeleteChannel(channel);
|
||||
models.push(...await prepareDeleteChannel(channel));
|
||||
let teamId = channel.teamId;
|
||||
if (teamId) {
|
||||
teamId = await queryCurrentTeamId(database);
|
||||
|
|
@ -98,7 +107,7 @@ export const localRemoveUserFromChannel = async (serverUrl: string, channelId: s
|
|||
if (system) {
|
||||
models.push(...system);
|
||||
}
|
||||
if (models.length) {
|
||||
if (models.length && !prepareRecordsOnly) {
|
||||
try {
|
||||
await operator.batchRecords(models);
|
||||
} catch {
|
||||
|
|
@ -107,9 +116,10 @@ export const localRemoveUserFromChannel = async (serverUrl: string, channelId: s
|
|||
}
|
||||
}
|
||||
}
|
||||
return {models};
|
||||
};
|
||||
|
||||
export const localSetChannelDeleteAt = async (serverUrl: string, channelId: string, deleteAt: number) => {
|
||||
export const setChannelDeleteAt = async (serverUrl: string, channelId: string, deleteAt: number) => {
|
||||
const serverDatabase = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (!serverDatabase) {
|
||||
return;
|
||||
|
|
@ -196,3 +206,43 @@ export const resetMessageCount = async (serverUrl: string, channelId: string) =>
|
|||
return {error};
|
||||
}
|
||||
};
|
||||
|
||||
export async function updateChannelsDisplayName(serverUrl: string, channels: ChannelModel[], user: UserProfile, prepareRecordsOnly = false) {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (!database) {
|
||||
return {};
|
||||
}
|
||||
const currentUser = await queryCurrentUser(database.database);
|
||||
if (!currentUser) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const {config, license} = await queryCommonSystemValues(database.database);
|
||||
const preferences = await queryPreferencesByCategoryAndName(database.database, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.NAME_NAME_FORMAT);
|
||||
const displaySettings = getTeammateNameDisplaySetting(preferences, config, license);
|
||||
const models: Model[] = [];
|
||||
channels?.forEach(async (channel) => {
|
||||
let newDisplayName = '';
|
||||
if (channel.type === General.DM_CHANNEL) {
|
||||
newDisplayName = displayUsername(user, currentUser.locale, displaySettings);
|
||||
} else {
|
||||
const dbProfiles = await database.database.get<UserModel>(USER).query(Q.on(CHANNEL_MEMBERSHIP, Q.where('channel_id', channel.id))).fetch();
|
||||
const newProfiles: Array<UserModel|UserProfile> = dbProfiles.filter((u) => u.id !== user.id);
|
||||
newProfiles.push(user);
|
||||
newDisplayName = displayGroupMessageName(newProfiles, currentUser.locale, displaySettings, currentUser.id);
|
||||
}
|
||||
|
||||
if (channel.displayName !== newDisplayName) {
|
||||
channel.prepareUpdate((c) => {
|
||||
c.displayName = newDisplayName;
|
||||
});
|
||||
models.push(channel);
|
||||
}
|
||||
});
|
||||
|
||||
if (models.length && !prepareRecordsOnly) {
|
||||
database.operator.batchRecords(models);
|
||||
}
|
||||
|
||||
return {models};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export const fetchPostsForCurrentChannel = async (serverUrl: string) => {
|
|||
return fetchPostsForChannel(serverUrl, currentChannelId);
|
||||
};
|
||||
|
||||
export const fetchPostsForChannel = async (serverUrl: string, channelId: string) => {
|
||||
export const fetchPostsForChannel = async (serverUrl: string, channelId: string, fetchOnly = false) => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
|
|
@ -65,42 +65,42 @@ export const fetchPostsForChannel = async (serverUrl: string, channelId: string)
|
|||
// Here we should emit an event that fetching posts failed.
|
||||
}
|
||||
|
||||
let authors: UserProfile[] = [];
|
||||
if (data.posts?.length && data.order?.length) {
|
||||
const models: Model[] = [];
|
||||
try {
|
||||
const {authors} = await fetchPostAuthors(serverUrl, data.posts, true);
|
||||
if (authors?.length) {
|
||||
const users = await operator.handleUsers({
|
||||
users: authors,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
if (users.length) {
|
||||
models.push(...users);
|
||||
}
|
||||
}
|
||||
const {authors: fetchedAuthors} = await fetchPostAuthors(serverUrl, data.posts, true);
|
||||
authors = fetchedAuthors || [];
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('FETCH AUTHORS ERROR', error);
|
||||
}
|
||||
|
||||
const postModels = await operator.handlePosts({
|
||||
actionType,
|
||||
order: data.order,
|
||||
posts: data.posts,
|
||||
previousPostId: data.previousPostId,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
if (!fetchOnly) {
|
||||
const models = [];
|
||||
const postModels = await operator.handlePosts({
|
||||
actionType,
|
||||
order: data.order,
|
||||
posts: data.posts,
|
||||
previousPostId: data.previousPostId,
|
||||
prepareRecordsOnly: true,
|
||||
});
|
||||
if (postModels) {
|
||||
models.push(...postModels);
|
||||
}
|
||||
if (authors.length) {
|
||||
const userModels = await operator.handleUsers({users: authors, prepareRecordsOnly: true});
|
||||
if (userModels.length) {
|
||||
models.push(...userModels);
|
||||
}
|
||||
}
|
||||
|
||||
if (postModels.length) {
|
||||
models.push(...postModels);
|
||||
}
|
||||
|
||||
if (models.length) {
|
||||
await operator.batchRecords(models);
|
||||
if (models.length) {
|
||||
operator.batchRecords(models);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {posts: data.posts};
|
||||
return {posts: data.posts, order: data.order, authors, actionType, previousPostId: data.previousPostId};
|
||||
};
|
||||
|
||||
export const fetchPostsForUnreadChannels = async (serverUrl: string, channels: Channel[], memberships: ChannelMembership[], excludeChannelId?: string) => {
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ export const updateAllUsersSinceLastDisconnect = async (serverUrl: string) => {
|
|||
return {users: userUpdates};
|
||||
};
|
||||
|
||||
export const updateUsersNoLongerVisible = async (serverUrl: string): Promise<{error?: unknown}> => {
|
||||
export const updateUsersNoLongerVisible = async (serverUrl: string, prepareRecordsOnly = false): Promise<{error?: unknown; models?: Model[]}> => {
|
||||
let client: Client;
|
||||
try {
|
||||
client = NetworkManager.getClient(serverUrl);
|
||||
|
|
@ -373,12 +373,12 @@ export const updateUsersNoLongerVisible = async (serverUrl: string): Promise<{er
|
|||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
const models: Model[] = [];
|
||||
try {
|
||||
const knownUsers = new Set(await client.getKnownUsers());
|
||||
const currentUserId = await queryCurrentUserId(serverDatabase.database);
|
||||
knownUsers.add(currentUserId);
|
||||
|
||||
const models: Model[] = [];
|
||||
const allUsers = await queryAllUsers(serverDatabase.database);
|
||||
for (const user of allUsers) {
|
||||
if (!knownUsers.has(user.id)) {
|
||||
|
|
@ -386,7 +386,7 @@ export const updateUsersNoLongerVisible = async (serverUrl: string): Promise<{er
|
|||
models.push(user);
|
||||
}
|
||||
}
|
||||
if (models.length) {
|
||||
if (models.length && !prepareRecordsOnly) {
|
||||
serverDatabase.operator.batchRecords(models);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -394,7 +394,7 @@ export const updateUsersNoLongerVisible = async (serverUrl: string): Promise<{er
|
|||
return {error};
|
||||
}
|
||||
|
||||
return {};
|
||||
return {models};
|
||||
};
|
||||
|
||||
export const setStatus = async (serverUrl: string, status: UserStatus) => {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,89 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Model} from '@nozbe/watermelondb';
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {localRemoveUserFromChannel, localSetChannelDeleteAt, switchToChannel} from '@actions/local/channel';
|
||||
import {updateUsersNoLongerVisible} from '@actions/remote/user';
|
||||
import {removeCurrentUserFromChannel, setChannelDeleteAt, switchToChannel} from '@actions/local/channel';
|
||||
import {fetchMyChannel} from '@actions/remote/channel';
|
||||
import {fetchPostsForChannel} from '@actions/remote/post';
|
||||
import {fetchUsersByIds, updateUsersNoLongerVisible} from '@actions/remote/user';
|
||||
import Events from '@constants/events';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {queryActiveServer} from '@queries/app/servers';
|
||||
import {deleteChannelMembership, queryCurrentChannel} from '@queries/servers/channel';
|
||||
import {queryConfig, setCurrentChannelId} from '@queries/servers/system';
|
||||
import {deleteChannelMembership, prepareMyChannelsForTeam, queryChannelsById, queryCurrentChannel} from '@queries/servers/channel';
|
||||
import {prepareCommonSystemValues, queryConfig, setCurrentChannelId} from '@queries/servers/system';
|
||||
import {queryLastChannelFromTeam} from '@queries/servers/team';
|
||||
import {queryCurrentUser} from '@queries/servers/user';
|
||||
import {queryCurrentUser, queryUserById} from '@queries/servers/user';
|
||||
import {dismissAllModals, popToRoot} from '@screens/navigation';
|
||||
import {isTablet} from '@utils/helpers';
|
||||
import {isGuest} from '@utils/user';
|
||||
|
||||
export async function handleUserRemovedEvent(serverUrl: string, msg: any) {
|
||||
export async function handleUserAddedToChannelEvent(serverUrl: string, msg: any) {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (!database) {
|
||||
return;
|
||||
}
|
||||
const currentUser = await queryCurrentUser(database.database);
|
||||
const {team_id: teamId, channel_id: channelId, user_id: userId} = msg.data;
|
||||
|
||||
const models: Model[] = [];
|
||||
|
||||
try {
|
||||
const addedUser = queryUserById(database.database, userId);
|
||||
if (!addedUser) {
|
||||
// TODO Potential improvement https://mattermost.atlassian.net/browse/MM-40581
|
||||
const {users} = await fetchUsersByIds(serverUrl, [userId], true);
|
||||
if (users) {
|
||||
models.push(...await database.operator.handleUsers({users, prepareRecordsOnly: true}));
|
||||
}
|
||||
}
|
||||
|
||||
if (userId === currentUser?.id) {
|
||||
const {channels, memberships} = await fetchMyChannel(serverUrl, teamId, channelId, true);
|
||||
if (channels && memberships) {
|
||||
const prepare = await prepareMyChannelsForTeam(database.operator, teamId, channels, memberships);
|
||||
if (prepare) {
|
||||
const prepareModels = await Promise.all(prepare);
|
||||
const flattenedModels = prepareModels.flat();
|
||||
if (flattenedModels?.length > 0) {
|
||||
models.push(...flattenedModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const {posts, order, authors, actionType, previousPostId} = await fetchPostsForChannel(serverUrl, channelId, true);
|
||||
if (posts?.length && order && actionType) {
|
||||
models.push(...await database.operator.handlePosts({
|
||||
actionType,
|
||||
order,
|
||||
posts,
|
||||
previousPostId,
|
||||
prepareRecordsOnly: true,
|
||||
}));
|
||||
}
|
||||
|
||||
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]) {
|
||||
models.push(...await database.operator.handleChannelMembership({
|
||||
channelMemberships: [{channel_id: channelId, user_id: userId}],
|
||||
prepareRecordsOnly: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
database.operator.batchRecords(models);
|
||||
}
|
||||
|
||||
export async function handleUserRemovedFromChannelEvent(serverUrl: string, msg: any) {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (!database) {
|
||||
return;
|
||||
|
|
@ -28,14 +95,25 @@ export async function handleUserRemovedEvent(serverUrl: string, msg: any) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (user.id === msg.data.user_id) {
|
||||
localRemoveUserFromChannel(serverUrl, msg.data.channel_id);
|
||||
const userId = msg.data.user_id;
|
||||
const channelId = msg.data.channel_id;
|
||||
|
||||
if (isGuest(user.roles)) {
|
||||
updateUsersNoLongerVisible(serverUrl);
|
||||
const models: Model[] = [];
|
||||
|
||||
if (user.isGuest) {
|
||||
const {models: updateVisibleModels} = await updateUsersNoLongerVisible(serverUrl, true);
|
||||
if (updateVisibleModels) {
|
||||
models.push(...updateVisibleModels);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.id === userId) {
|
||||
const {models: removeUserModels} = await removeCurrentUserFromChannel(serverUrl, channelId, true);
|
||||
if (removeUserModels) {
|
||||
models.push(...removeUserModels);
|
||||
}
|
||||
|
||||
if (channel && channel.id === msg.data.channel_id) {
|
||||
if (channel && channel.id === channelId) {
|
||||
const currentServer = await queryActiveServer(DatabaseManager.appDatabase!.database);
|
||||
|
||||
if (currentServer?.url === serverUrl) {
|
||||
|
|
@ -46,16 +124,27 @@ export async function handleUserRemovedEvent(serverUrl: string, msg: any) {
|
|||
if (await isTablet()) {
|
||||
const channelToJumpTo = await queryLastChannelFromTeam(database.database, channel?.teamId);
|
||||
if (channelToJumpTo) {
|
||||
switchToChannel(serverUrl, channelToJumpTo);
|
||||
} // TODO else jump to "join a channel" screen
|
||||
const {models: switchChannelModels} = await switchToChannel(serverUrl, channelToJumpTo, '', true);
|
||||
if (switchChannelModels) {
|
||||
models.push(...switchChannelModels);
|
||||
}
|
||||
} // TODO else jump to "join a channel" screen https://mattermost.atlassian.net/browse/MM-41051
|
||||
} else {
|
||||
setCurrentChannelId(database.operator, '');
|
||||
const currentChannelModels = await prepareCommonSystemValues(database.operator, {currentChannelId: ''});
|
||||
if (currentChannelModels?.length) {
|
||||
models.push(...currentChannelModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deleteChannelMembership(database.operator, msg.data.user_id, msg.data.channel_id);
|
||||
const {models: deleteMemberModels} = await deleteChannelMembership(database.operator, userId, channelId, true);
|
||||
if (deleteMemberModels) {
|
||||
models.push(...deleteMemberModels);
|
||||
}
|
||||
}
|
||||
|
||||
database.operator.batchRecords(models);
|
||||
}
|
||||
|
||||
export async function handleChannelDeletedEvent(serverUrl: string, msg: any) {
|
||||
|
|
@ -72,14 +161,14 @@ export async function handleChannelDeletedEvent(serverUrl: string, msg: any) {
|
|||
|
||||
const config = await queryConfig(database.database);
|
||||
|
||||
await localSetChannelDeleteAt(serverUrl, msg.data.channel_id, msg.data.delete_at);
|
||||
await setChannelDeleteAt(serverUrl, msg.data.channel_id, msg.data.delete_at);
|
||||
|
||||
if (isGuest(user.roles)) {
|
||||
if (user.isGuest) {
|
||||
updateUsersNoLongerVisible(serverUrl);
|
||||
}
|
||||
|
||||
if (config?.ExperimentalViewArchivedChannels !== 'true') {
|
||||
localRemoveUserFromChannel(serverUrl, msg.data.channel_id);
|
||||
removeCurrentUserFromChannel(serverUrl, msg.data.channel_id);
|
||||
|
||||
if (currentChannel && currentChannel.id === msg.data.channel_id) {
|
||||
const currentServer = await queryActiveServer(DatabaseManager.appDatabase!.database);
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ import {prepareMyChannelsForTeam} from '@queries/servers/channel';
|
|||
import {queryCommonSystemValues, queryConfig, queryWebSocketLastDisconnected} from '@queries/servers/system';
|
||||
import {queryCurrentUser} from '@queries/servers/user';
|
||||
|
||||
import {handleChannelDeletedEvent, handleUserRemovedEvent} from './channel';
|
||||
import {handleChannelDeletedEvent, handleUserAddedToChannelEvent, handleUserRemovedFromChannelEvent} from './channel';
|
||||
import {handlePreferenceChangedEvent, handlePreferencesChangedEvent, handlePreferencesDeletedEvent} from './preferences';
|
||||
import {handleLeaveTeamEvent} from './teams';
|
||||
import {handleUserUpdatedEvent} from './users';
|
||||
|
||||
import type {Model} from '@nozbe/watermelondb';
|
||||
|
||||
|
|
@ -122,7 +123,7 @@ async function doReconnect(serverUrl: string) {
|
|||
const viewArchivedChannels = config?.ExperimentalViewArchivedChannels === 'true';
|
||||
|
||||
if (!stillMemberOfCurrentChannel) {
|
||||
handleUserRemovedEvent(serverUrl, {data: {user_id: currentUserId, channel_id: currentChannelId}});
|
||||
handleUserRemovedFromChannelEvent(serverUrl, {data: {user_id: currentUserId, channel_id: currentChannelId}});
|
||||
} else if (!channelStillExist ||
|
||||
(!viewArchivedChannels && channelStillExist.delete_at !== 0)
|
||||
) {
|
||||
|
|
@ -177,16 +178,14 @@ export async function handleEvent(serverUrl: string, msg: any) {
|
|||
|
||||
// return dispatch(handleTeamAddedEvent(msg));
|
||||
case WebsocketEvents.USER_ADDED:
|
||||
handleUserAddedToChannelEvent(serverUrl, msg);
|
||||
break;
|
||||
|
||||
// return dispatch(handleUserAddedEvent(msg));
|
||||
case WebsocketEvents.USER_REMOVED:
|
||||
handleUserRemovedEvent(serverUrl, msg);
|
||||
handleUserRemovedFromChannelEvent(serverUrl, msg);
|
||||
break;
|
||||
case WebsocketEvents.USER_UPDATED:
|
||||
handleUserUpdatedEvent(serverUrl, msg);
|
||||
break;
|
||||
|
||||
// return dispatch(handleUserUpdatedEvent(msg));
|
||||
case WebsocketEvents.ROLE_ADDED:
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import {queryCurrentTeamId} from '@queries/servers/system';
|
|||
import {queryLastTeam} from '@queries/servers/team';
|
||||
import {queryCurrentUser} from '@queries/servers/user';
|
||||
import {dismissAllModals, popToRoot} from '@screens/navigation';
|
||||
import {isGuest} from '@utils/user';
|
||||
|
||||
export async function handleLeaveTeamEvent(serverUrl: string, msg: any) {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl];
|
||||
|
|
@ -31,7 +30,7 @@ export async function handleLeaveTeamEvent(serverUrl: string, msg: any) {
|
|||
await removeUserFromTeam(serverUrl, msg.data.team_id);
|
||||
fetchAllTeams(serverUrl);
|
||||
|
||||
if (isGuest(user.roles)) {
|
||||
if (user.isGuest) {
|
||||
updateUsersNoLongerVisible(serverUrl);
|
||||
}
|
||||
|
||||
|
|
|
|||
62
app/actions/websocket/users.ts
Normal file
62
app/actions/websocket/users.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
|
||||
import {updateChannelsDisplayName} from '@actions/local/channel';
|
||||
import {fetchMe} from '@actions/remote/user';
|
||||
import {General} from '@constants';
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {queryCurrentUser} from '@queries/servers/user';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
|
||||
const {SERVER: {CHANNEL, CHANNEL_MEMBERSHIP}} = MM_TABLES;
|
||||
|
||||
export async function handleUserUpdatedEvent(serverUrl: string, msg: any) {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (!database) {
|
||||
return;
|
||||
}
|
||||
const currentUser = await queryCurrentUser(database.database);
|
||||
if (!currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
const user: UserProfile = msg.data.user;
|
||||
|
||||
if (user.id === currentUser.id) {
|
||||
if (user.update_at > (currentUser?.updateAt || 0)) {
|
||||
// Need to request me to make sure we don't override with sanitized fields from the
|
||||
// websocket event
|
||||
// TODO Potential improvement https://mattermost.atlassian.net/browse/MM-40582
|
||||
fetchMe(serverUrl, false);
|
||||
|
||||
// Update GMs display name if locale has changed
|
||||
if (user.locale !== currentUser.locale) {
|
||||
const channels = await database.database.get<ChannelModel>(CHANNEL).query(
|
||||
Q.where('type', Q.eq(General.GM_CHANNEL))).fetch();
|
||||
const {models} = await updateChannelsDisplayName(serverUrl, channels, user, true);
|
||||
if (models?.length) {
|
||||
database.operator.batchRecords(models);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
database.operator.handleUsers({users: [user], prepareRecordsOnly: false});
|
||||
|
||||
const channels = await database.database.get<ChannelModel>(CHANNEL).query(
|
||||
Q.where('type', Q.oneOf([General.DM_CHANNEL, General.GM_CHANNEL])),
|
||||
Q.on(CHANNEL_MEMBERSHIP, Q.where('user_id', user.id))).fetch();
|
||||
if (!channels?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {models} = await updateChannelsDisplayName(serverUrl, channels, user, true);
|
||||
|
||||
if (models?.length) {
|
||||
database.operator.batchRecords(models);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ export const isRecordGroupMembershipEqualToRaw = (record: GroupMembershipModel,
|
|||
return raw.user_id === record.userId && raw.group_id === record.groupId;
|
||||
};
|
||||
|
||||
export const isRecordChannelMembershipEqualToRaw = (record: ChannelMembershipModel, raw: ChannelMembership) => {
|
||||
export const isRecordChannelMembershipEqualToRaw = (record: ChannelMembershipModel, raw: Pick<ChannelMembership, 'user_id' | 'channel_id'>) => {
|
||||
return raw.user_id === record.userId && raw.channel_id === record.channelId;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ const PostHandler = (superclass: any) => class extends superclass {
|
|||
* @param {string[]} handlePosts.orders
|
||||
* @param {RawPost[]} handlePosts.values
|
||||
* @param {string | undefined} handlePosts.previousPostId
|
||||
* @param {boolean | undefined} handlePosts.prepareRecordsOnly
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
handlePosts = async ({actionType, order, posts, previousPostId = '', prepareRecordsOnly = false}: HandlePostsArgs): Promise<Model[]> => {
|
||||
|
|
|
|||
|
|
@ -214,14 +214,25 @@ export const queryCurrentChannel = async (database: Database) => {
|
|||
return undefined;
|
||||
};
|
||||
|
||||
export const deleteChannelMembership = async (operator: ServerDataOperator, userId: string, channelId: string) => {
|
||||
export const deleteChannelMembership = async (operator: ServerDataOperator, userId: string, channelId: string, prepareRecordsOnly = false) => {
|
||||
try {
|
||||
const channelMembership = await operator.database.get(CHANNEL_MEMBERSHIP).query(Q.where('user_id', Q.eq(userId)), Q.where('channel_id', Q.eq(channelId))).fetch();
|
||||
const models: Model[] = [];
|
||||
for (const membership of channelMembership) {
|
||||
models.push(membership.prepareDestroyPermanently());
|
||||
}
|
||||
await operator.batchRecords(models);
|
||||
if (models.length && !prepareRecordsOnly) {
|
||||
await operator.batchRecords(models);
|
||||
}
|
||||
return {models};
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
};
|
||||
|
||||
export const addChannelMembership = async (operator: ServerDataOperator, userId: string, channelId: string) => {
|
||||
try {
|
||||
await operator.handleChannelMembership({channelMemberships: [{channel_id: channelId, user_id: userId}], prepareRecordsOnly: false});
|
||||
return {};
|
||||
} catch (error) {
|
||||
return {error};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export function displayUsername(user?: UserProfile | UserModel, locale?: string,
|
|||
return name;
|
||||
}
|
||||
|
||||
export function displayGroupMessageName(users: UserProfile[], locale?: string, teammateDisplayNameSetting?: string, excludeUserId?: string) {
|
||||
export function displayGroupMessageName(users: Array<UserProfile | UserModel>, locale?: string, teammateDisplayNameSetting?: string, excludeUserId?: string) {
|
||||
const names: string[] = [];
|
||||
const sortUsernames = (a: string, b: string) => {
|
||||
return a.localeCompare(b, locale || DEFAULT_LOCALE, {numeric: true});
|
||||
|
|
|
|||
1
types/api/channels.d.ts
vendored
1
types/api/channels.d.ts
vendored
|
|
@ -5,6 +5,7 @@ type ChannelStats = {
|
|||
channel_id: string;
|
||||
guest_count: number;
|
||||
member_count: number;
|
||||
guest_count: number;
|
||||
pinnedpost_count: number;
|
||||
};
|
||||
type ChannelNotifyProps = {
|
||||
|
|
|
|||
2
types/database/database.d.ts
vendored
2
types/database/database.d.ts
vendored
|
|
@ -223,7 +223,7 @@ export type HandleGroupArgs = PrepareOnly & {
|
|||
};
|
||||
|
||||
export type HandleChannelMembershipArgs = PrepareOnly & {
|
||||
channelMemberships: ChannelMember[];
|
||||
channelMemberships: Array<Pick<ChannelMembership, 'user_id' | 'channel_id'>>;
|
||||
};
|
||||
|
||||
export type HandleGroupMembershipArgs = PrepareOnly & {
|
||||
|
|
|
|||
1
types/database/raw_values.d.ts
vendored
1
types/database/raw_values.d.ts
vendored
|
|
@ -122,3 +122,4 @@ type RawValue =
|
|||
| TeamSearchHistory
|
||||
| TermsOfService
|
||||
| UserProfile
|
||||
| Pick<ChannelMembership, 'channel_id' | 'user_id'>
|
||||
|
|
|
|||
Loading…
Reference in a new issue