From a8db924eae2ef951b68f9f732812873b005d9187 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Thu, 14 May 2026 12:33:58 +0000 Subject: [PATCH] fix: users.presence ignoring comma-separated IDs after OpenAPI migration (#40513) --- .changeset/fix-presence-comma-ids.md | 6 +++ apps/meteor/tests/end-to-end/api/users.ts | 42 +++++++++++++++++++ .../src/v1/users/UsersPresenceParamsGET.ts | 3 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-presence-comma-ids.md diff --git a/.changeset/fix-presence-comma-ids.md b/.changeset/fix-presence-comma-ids.md new file mode 100644 index 0000000000000..c85d20785e3a6 --- /dev/null +++ b/.changeset/fix-presence-comma-ids.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/meteor': patch +'@rocket.chat/rest-typings': patch +--- + +Fixes the `users.presence` endpoint returning an empty array when called with multiple comma-separated IDs, caused by `ajvQuery` coercing the string into a single-element array after the OpenAPI migration \ No newline at end of file diff --git a/apps/meteor/tests/end-to-end/api/users.ts b/apps/meteor/tests/end-to-end/api/users.ts index 30e59d9a554aa..348d3643a7292 100644 --- a/apps/meteor/tests/end-to-end/api/users.ts +++ b/apps/meteor/tests/end-to-end/api/users.ts @@ -1392,6 +1392,48 @@ describe('[Users]', () => { .end(done); }); + it('should return presence for a single id', async () => { + const res = await request + .get(api('users.presence')) + .query({ ids: 'rocket.cat' }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200); + + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('full', false); + expect(res.body).to.have.property('users').that.is.an('array').with.lengthOf(1); + expect(res.body.users[0]).to.have.property('_id', 'rocket.cat'); + }); + + it('should correctly parse comma-separated ids and not return an empty result', async () => { + const res = await request + .get(api('users.presence')) + .query({ ids: `rocket.cat,${credentials['X-User-Id']}` }) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200); + + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('full', false); + // only rocket.cat is guaranteed to be online; admin may be offline + expect(res.body.users.map((u: IUser) => u._id)).to.include('rocket.cat'); + }); + + it('should return presence for repeated ids params', async () => { + const res = await request + .get(api('users.presence')) + .query(`ids=rocket.cat&ids=${credentials['X-User-Id']}`) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200); + + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('full', false); + // only rocket.cat is guaranteed to be online; admin may be offline + expect(res.body.users.map((u: IUser) => u._id)).to.include('rocket.cat'); + }); + it('should return full list of online users for more than 10 minutes in the past', (done) => { const date = new Date(); date.setMinutes(date.getMinutes() - 11); diff --git a/packages/rest-typings/src/v1/users/UsersPresenceParamsGET.ts b/packages/rest-typings/src/v1/users/UsersPresenceParamsGET.ts index 9fcd9f49b9fd3..d35a98462c2ad 100644 --- a/packages/rest-typings/src/v1/users/UsersPresenceParamsGET.ts +++ b/packages/rest-typings/src/v1/users/UsersPresenceParamsGET.ts @@ -10,7 +10,8 @@ const UsersPresenceParamsGetSchema = { properties: { from: { type: 'string', nullable: true }, ids: { - anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + type: ['string', 'array'], + items: { type: 'string' }, }, }, additionalProperties: false,