diff --git a/.changeset/pretty-ladybugs-sneeze.md b/.changeset/pretty-ladybugs-sneeze.md new file mode 100644 index 00000000000..88aa14149df --- /dev/null +++ b/.changeset/pretty-ladybugs-sneeze.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/ddp-streamer": patch +--- + +Fixes page loading during reconnections diff --git a/apps/meteor/app/authentication/server/startup/index.js b/apps/meteor/app/authentication/server/startup/index.js index 10ba3fd4415..0577ceac0ba 100644 --- a/apps/meteor/app/authentication/server/startup/index.js +++ b/apps/meteor/app/authentication/server/startup/index.js @@ -23,12 +23,24 @@ import { setAvatarFromServiceWithValidation } from '../../../lib/server/function import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener'; import * as Mailer from '../../../mailer/server/api'; import { settings } from '../../../settings/server'; +import { getBaseUserFields } from '../../../utils/server/functions/getBaseUserFields'; import { safeGetMeteorUser } from '../../../utils/server/functions/safeGetMeteorUser'; import { isValidAttemptByUser, isValidLoginAttemptByIp } from '../lib/restrictLoginAttempts'; Accounts.config({ forbidClientAccountCreation: true, }); +/** + * Accounts calls `_initServerPublications` and holds the `_defaultPublishFields`, without Object.assign its not possible + * to extend the projection + * + * the idea is to send all required fields to the client during login + * we tried `defaultFieldsSelector` , but it changes all Meteor.userAsync projections which is undesirable + * + * + * we are removing the status here because meteor send 'offline' + */ +Object.assign(Accounts._defaultPublishFields.projection, (({ status, ...rest }) => rest)(getBaseUserFields())); Meteor.startup(() => { settings.watchMultiple(['Accounts_LoginExpiration', 'Site_Name', 'From_Email'], () => { diff --git a/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts b/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts index 602a0eddb8c..10ea6d9453b 100644 --- a/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts +++ b/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts @@ -83,6 +83,9 @@ export class CachedCollection extends Emitter< CachedCollectionManager.onLogin(() => { void this.init(); }); + Accounts.onLogout(() => { + this.ready.set(false); + }); } protected get eventName(): `${Name}-changed` | `${string}/${Name}-changed` { @@ -342,8 +345,6 @@ export class CachedCollection extends Emitter< } async init() { - this.ready.set(false); - if (await this.loadFromCache()) { this.trySync(); } else { diff --git a/ee/apps/ddp-streamer/src/DDPStreamer.ts b/ee/apps/ddp-streamer/src/DDPStreamer.ts index 275f26ae05e..2ba89ced713 100644 --- a/ee/apps/ddp-streamer/src/DDPStreamer.ts +++ b/ee/apps/ddp-streamer/src/DDPStreamer.ts @@ -2,6 +2,7 @@ import crypto from 'crypto'; import { MeteorService, Presence, ServiceClass } from '@rocket.chat/core-services'; import { InstanceStatus } from '@rocket.chat/instance-status'; +import { Users } from '@rocket.chat/models'; import polka from 'polka'; import { throttle } from 'underscore'; import WebSocket from 'ws'; @@ -123,12 +124,34 @@ export class DDPStreamer extends ServiceClass { } }); - server.on(DDP_EVENTS.LOGGED, (info) => { + async function sendUserData(client: Client, userId: string) { + // TODO figure out what fields to send. maybe to to export function getBaseUserFields to a package + const loggedUser = await Users.findOneById(userId, { + projection: { name: 1, username: 1, settings: 1, roles: 1, active: 1, statusLivechat: 1, statusDefault: 1, status: 1 }, + }); + if (!loggedUser) { + return; + } + + // using setImmediate here so login's method result is sent before we send the user data + setImmediate(async () => server.added(client, 'users', userId, loggedUser)); + } + server.on(DDP_EVENTS.LOGGED, async (info: Client) => { const { userId, connection } = info; - Presence.newConnection(userId, connection.id, nodeID); + if (!userId) { + throw new Error('User not logged in'); + } + + await Presence.newConnection(userId, connection.id, nodeID); + this.updateConnections(); + // mimic Meteor's default publication that sends user data after login + await sendUserData(info, userId); + + server.emit('presence', { userId, connection }); + this.api?.broadcast('accounts.login', { userId, connection }); });