Skip to content

refactor: migrate users.list endpoint to ajv schema#39368

Open
krishikajain28 wants to merge 16 commits intoRocketChat:developfrom
krishikajain28:fix/migrate-users-list-schema
Open

refactor: migrate users.list endpoint to ajv schema#39368
krishikajain28 wants to merge 16 commits intoRocketChat:developfrom
krishikajain28:fix/migrate-users-list-schema

Conversation

@krishikajain28
Copy link

@krishikajain28 krishikajain28 commented Mar 5, 2026

Proposed changes (including screenshots)

This PR updates the legacy users.list REST API endpoint to use strict AJV schema validation.

  • Swapped out the old manual query validation for ajv.compile on all query params (offset, count, sort, fields, query).
  • Added a strict response schema to enforce that the endpoint always returns the required shape (users, count, offset, total).
  • The underlying MongoDB aggregation and permission checks remain untouched to prevent regressions.

(Note: Tested the UI after the migration, attaching screenshot below showing the Directory still loading users correctly).
image

Issue(s)

N/A

Steps to test or reproduce

  1. Spin up the local development environment using yarn dsv.
  2. Log in and click the "Directory" (globe icon) on the left sidebar.
  3. Switch to the "Users" tab.
  4. Verify the user list loads properly, pagination works, and no 400/500 errors appear in the server terminal or browser console.

Further comments

Kept the scope strictly to adding the validation layer to avoid breaking any existing client integrations.

Summary by CodeRabbit

  • New Features
    • Restored an authenticated users.list endpoint with permissions, enhanced query validation, filtering, sorting and pagination.
    • Listing responses now return users plus pagination metadata (users, count, offset, total) and include a success flag.
    • Avatar suggestion responses now follow the unified listing response format and include the success flag.

@krishikajain28 krishikajain28 requested a review from a team as a code owner March 5, 2026 11:46
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Mar 5, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Mar 5, 2026

⚠️ No Changeset found

Latest commit: c425e69

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new server-side GET users.list route with auth and permission checks, AJV-validated inputs/outputs, and a paginated MongoDB aggregation response (users, count, offset, total, success). Also updates avatar suggestion response schema. Separately, the public REST typings removed the '/v1/users.list' endpoint signature.

Changes

Cohort / File(s) Summary
API Users Endpoint
apps/meteor/app/api/server/v1/users.ts
Adds a new API.v1.addRoute('users.list', ...) GET implementation with authRequired, permissionsRequired: ['view-d-room'], AJV input/output schemas (including 400/403), parsing of offset/count/sort/fields/query, and a MongoDB aggregation returning { users, count, offset, total, success }. Extends users.getAvatarSuggestion 200 response to include success.
REST Typings
packages/rest-typings/src/v1/users.ts
Removes the '/v1/users.list' GET endpoint signature from UsersEndpoints, altering the public API typings for listing users (previous PaginatedRequest/Result signature deleted).

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as API.v1.users.list
  participant Auth as Auth/Permissions
  participant DB as MongoDB

  Client->>API: GET /api/v1/users.list?query...&offset=&count=&sort=&fields=
  API->>Auth: validate auth & permissions
  Auth-->>API: authorized
  API->>API: AJV validate & parse params
  API->>DB: aggregation pipeline (filter, projection, facet: results + total)
  DB-->>API: { results[], total }
  API-->>Client: { users: results, count: results.length, offset, total, success: true }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

type: chore

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: migrating the users.list endpoint to use AJV schema validation instead of manual validation, which aligns with the PR's core objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can customize the high-level summary generated by CodeRabbit.

Configure the reviews.high_level_summary_instructions setting to provide custom instructions for generating the high-level summary.

@CLAassistant
Copy link

CLAassistant commented Mar 5, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/users.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/users.ts:823">
P1: `users.getAvatarSuggestion` was unintentionally removed by replacing its route entry with `users.list`, causing an API regression for existing clients.</violation>

<violation number="2" location="apps/meteor/app/api/server/v1/users.ts:862">
P1: `users.list` 200 response schema omits `success` even though `API.v1.success(...)` returns it, causing schema mismatch with `additionalProperties: false`.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/app/api/server/v1/users.ts`:
- Around line 846-864: The response schema compiled with ajv.compile for the
users list is missing the top-level "success" boolean that API.v1.success()
injects; because additionalProperties is false this will fail validation. Update
the AJV schema used in this block (the ajv.compile<{ users: IUser[]; count:
number; offset: number; total: number; }>) to include a "success" property of
type "boolean" and add "success" to the required array so the schema matches
responses produced by API.v1.success().
- Around line 867-877: The new action() flow omitted the prior permission check
for "view-outside-room", causing a security regression; update action() so that
when constructing nonEmptyQuery (currently calling getNonEmptyQuery(query, await
hasPermissionAsync(this.userId, 'view-full-other-user-info'))), you also
evaluate whether the caller has hasPermissionAsync(this.userId,
'view-outside-room') (and respect the
API_Apply_permission_view-outside-room_on_users-list setting) and pass the
combined/appropriate boolean into getNonEmptyQuery (or otherwise gate the query
construction) so the users list honors the original view-outside-room permission
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 98ef8de3-1303-4d64-881a-5afa7fc860b6

📥 Commits

Reviewing files that changed from the base of the PR and between b8b8611 and 4ff7d07.

📒 Files selected for processing (1)
  • apps/meteor/app/api/server/v1/users.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/api/server/v1/users.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
🔇 Additional comments (2)
apps/meteor/app/api/server/v1/users.ts (2)

919-961: LGTM!

The MongoDB aggregation pipeline implementation is correct. The facet pattern for combining paginated results with total count is efficient, and the fallback for empty totalCount array ({ total: 0 }) handles edge cases properly.


478-590: 🛠️ Refactor suggestion | 🟠 Major

Remove commented-out code instead of preserving it.

Large blocks of commented code should be removed rather than kept in the codebase. Version control (git) preserves history if the old implementation needs to be referenced later.

As per coding guidelines: "Avoid code comments in the implementation".

⛔ Skipped due to learnings
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to **/*.{ts,tsx,js} : Avoid code comments in the implementation
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39230
File: apps/meteor/app/api/server/v1/chat.ts:214-222
Timestamp: 2026-03-03T11:11:48.541Z
Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
apps/meteor/app/api/server/v1/users.ts (2)

847-865: ⚠️ Potential issue | 🔴 Critical

Response schema must include success to match API.v1.success() output.

With additionalProperties: false, the current 200 schema rejects the top-level success boolean added by API.v1.success(...).

🐛 Proposed fix
-				200: ajv.compile<{
-					users: IUser[];
-					count: number;
-					offset: number;
-					total: number;
-				}>({
+				200: ajv.compile<{
+					users: IUser[];
+					count: number;
+					offset: number;
+					total: number;
+					success: boolean;
+				}>({
 					type: 'object',
 					properties: {
 						users: {
 							type: 'array',
 							items: { type: 'object' },
 						},
 						count: { type: 'number' },
 						offset: { type: 'number' },
 						total: { type: 'number' },
+						success: { type: 'boolean', enum: [true] },
 					},
-					required: ['users', 'count', 'offset', 'total'],
+					required: ['users', 'count', 'offset', 'total', 'success'],
 					additionalProperties: false,
 				}),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/api/server/v1/users.ts` around lines 847 - 865, The 200
response schema compiled via ajv.compile for the users endpoint currently has
additionalProperties: false and thus rejects the top-level success boolean
returned by API.v1.success(); update that schema (the object passed to
ajv.compile in this users response block) to declare a "success" property with
type "boolean" and include "success" in the required array so the
API.v1.success(...) output is accepted.

869-879: ⚠️ Potential issue | 🟠 Major

Restore view-outside-room enforcement for users.list.

The new handler dropped the setting-gated view-outside-room permission check that existed in the previous implementation, changing access behavior.

🛡️ Proposed fix
 		async function action() {
+			if (
+				settings.get('API_Apply_permission_view-outside-room_on_users-list') &&
+				!(await hasPermissionAsync(this.userId, 'view-outside-room'))
+			) {
+				return API.v1.forbidden();
+			}
+
 			const { offset, count } = await getPaginationItems(this.queryParams);
 			const { sort, fields, query } = await this.parseJsonQuery();

Based on learnings: "In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/api/server/v1/users.ts` around lines 869 - 879, Restore the
dropped "view-outside-room" permission check in the users.list handler by
calling hasPermissionAsync(this.userId, 'view-outside-room') and using its
boolean result to preserve original access semantics; specifically, pass that
permission flag into getNonEmptyQuery (or, if the original implementation
enforced filtering after building the query, apply the same filtering logic when
the permission is false) so the query/result set is restricted for users without
view-outside-room exactly as before; update the block around
getNonEmptyQuery/query handling (referencing getNonEmptyQuery and the users.list
handler) to reintroduce this permission check without changing other logic.
🧹 Nitpick comments (1)
apps/meteor/app/api/server/v1/users.ts (1)

479-591: Remove commented-out legacy route and inline implementation comments.

Keeping the large commented users.list block and inline comments in the active path adds noise and conflicts with repository guidance.

As per coding guidelines: "Avoid code comments in the implementation".

Also applies to: 880-895

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/api/server/v1/users.ts` around lines 479 - 591, Remove the
large commented-out legacy API.v1.addRoute block for 'users.list' (the entire
commented route and its inner async get() implementation) and strip any inline
explanatory comments left in that area; ensure you only remove commented code
(no active logic) and leave intact the real users list route/handlers elsewhere,
referencing API.v1.addRoute('users.list') and the async get() implementation to
locate the block to delete.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/meteor/app/api/server/v1/users.ts`:
- Around line 847-865: The 200 response schema compiled via ajv.compile for the
users endpoint currently has additionalProperties: false and thus rejects the
top-level success boolean returned by API.v1.success(); update that schema (the
object passed to ajv.compile in this users response block) to declare a
"success" property with type "boolean" and include "success" in the required
array so the API.v1.success(...) output is accepted.
- Around line 869-879: Restore the dropped "view-outside-room" permission check
in the users.list handler by calling hasPermissionAsync(this.userId,
'view-outside-room') and using its boolean result to preserve original access
semantics; specifically, pass that permission flag into getNonEmptyQuery (or, if
the original implementation enforced filtering after building the query, apply
the same filtering logic when the permission is false) so the query/result set
is restricted for users without view-outside-room exactly as before; update the
block around getNonEmptyQuery/query handling (referencing getNonEmptyQuery and
the users.list handler) to reintroduce this permission check without changing
other logic.

---

Nitpick comments:
In `@apps/meteor/app/api/server/v1/users.ts`:
- Around line 479-591: Remove the large commented-out legacy API.v1.addRoute
block for 'users.list' (the entire commented route and its inner async get()
implementation) and strip any inline explanatory comments left in that area;
ensure you only remove commented code (no active logic) and leave intact the
real users list route/handlers elsewhere, referencing
API.v1.addRoute('users.list') and the async get() implementation to locate the
block to delete.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d7e8dddf-f7c9-4636-856d-020c3bef60b2

📥 Commits

Reviewing files that changed from the base of the PR and between 4ff7d07 and 68fcec0.

📒 Files selected for processing (1)
  • apps/meteor/app/api/server/v1/users.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/api/server/v1/users.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-03-03T11:11:48.541Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39230
File: apps/meteor/app/api/server/v1/chat.ts:214-222
Timestamp: 2026-03-03T11:11:48.541Z
Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
🔇 Additional comments (1)
apps/meteor/app/api/server/v1/users.ts (1)

824-963: ⚠️ Potential issue | 🟠 Major

Potential client break: avatar suggestion consumer still targets /v1/users.getAvatarSuggestion.

apps/meteor/client/components/avatar/UserAvatarEditor/useUserAvatarSuggestions.ts:1-11 still calls /v1/users.getAvatarSuggestion and expects data.suggestions; this route/shape change to users.list risks breaking avatar suggestions unless backward compatibility is kept.

⛔ Skipped due to learnings
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/meteor/app/api/server/v1/users.ts (1)

479-591: Remove the commented-out legacy users.list block.

This is now a dead second copy of the endpoint beside the live implementation, which will drift and make future reviews harder. A follow-up is fine if you want to keep this PR narrowly scoped. As per coding guidelines, "Avoid code comments in the implementation."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/api/server/v1/users.ts` around lines 479 - 591, Remove the
entire commented-out legacy API.v1.addRoute block for 'users.list' (the large
commented block starting with "API.v1.addRoute(" and ending with the matching
closing parenthesis and semicolon) so only the active implementation remains;
locate the commented block around the API.v1.addRoute('users.list', ...) symbol
in apps/meteor/app/api/server/v1/users.ts and delete it wholesale to avoid
duplicate dead code and future drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/meteor/app/api/server/v1/users.ts`:
- Around line 479-591: Remove the entire commented-out legacy API.v1.addRoute
block for 'users.list' (the large commented block starting with
"API.v1.addRoute(" and ending with the matching closing parenthesis and
semicolon) so only the active implementation remains; locate the commented block
around the API.v1.addRoute('users.list', ...) symbol in
apps/meteor/app/api/server/v1/users.ts and delete it wholesale to avoid
duplicate dead code and future drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b57f162-4c8e-4f3e-83cf-42177f9f4038

📥 Commits

Reviewing files that changed from the base of the PR and between 68fcec0 and 916fcda.

📒 Files selected for processing (1)
  • apps/meteor/app/api/server/v1/users.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/api/server/v1/users.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:09.561Z
Learning: In RocketChat/Rocket.Chat OpenAPI migration PRs for apps/meteor/app/api/server/v1 endpoints, maintainers prefer to avoid any logic changes; style-only cleanups (like removing inline comments) may be deferred to follow-ups to keep scope tight.
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-03-03T11:11:48.541Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 39230
File: apps/meteor/app/api/server/v1/chat.ts:214-222
Timestamp: 2026-03-03T11:11:48.541Z
Learning: In apps/meteor/server/lib/moderation/reportMessage.ts, the reportMessage function validates that description is not empty or whitespace-only with `if (!description.trim())`. When migrating the chat.reportMessage endpoint to OpenAPI, adding minLength validation to the schema preserves this existing behavior.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-23T17:53:06.802Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 35995
File: apps/meteor/app/api/server/v1/rooms.ts:1107-1112
Timestamp: 2026-02-23T17:53:06.802Z
Learning: During PR reviews that touch endpoint files under apps/meteor/app/api/server/v1, enforce strict scope: if a PR targets a specific endpoint (e.g., rooms.favorite), do not propose changes to unrelated endpoints (e.g., rooms.invite) unless maintainers explicitly request them. Focus feedback on the touched endpoint's behavior, API surface, and related tests; avoid broad cross-endpoint changes in the same PR unless requested.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-24T19:09:01.522Z
Learnt from: ahmed-n-abdeltwab
Repo: RocketChat/Rocket.Chat PR: 38974
File: apps/meteor/app/api/server/v1/im.ts:220-221
Timestamp: 2026-02-24T19:09:01.522Z
Learning: In Rocket.Chat OpenAPI migration PRs for endpoints under apps/meteor/app/api/server/v1, avoid introducing logic changes. Only perform scope-tight changes that preserve behavior; style-only cleanups (e.g., removing inline comments) may be deferred to follow-ups to keep the migration PR focused.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • apps/meteor/app/api/server/v1/users.ts
🔇 Additional comments (1)
apps/meteor/app/api/server/v1/users.ts (1)

875-895: No changes needed. The route configuration correctly omits queryOperations because the new implementation does not rely on route-level metadata for query validation. The parseJsonQuery() method only applies metadata-based validation when queryFields is defined on the route (line 142-143 of parseJsonQuery.ts), and the new route does not define queryFields. Instead, the action function performs explicit validation at lines 945–965 with hardcoded allowed operations including $or and $and, which is independent of route metadata and will continue to work as before. This design is cleaner and avoids unnecessary metadata.

			> Likely an incorrect or invalid review comment.

Copy link
Contributor

@ahmed-n-abdeltwab ahmed-n-abdeltwab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where are the remaining steps?

@krishikajain28
Copy link
Author

where are the remaining steps?

Hi @ahmed-n-abdeltwab. Do you mean the typing export steps (ExtractRoutesFromAPI and declare module '@rocket.chat/rest-typings') and removing the old manual typings? If so, I will add those to the PR immediately. Let me know if there is anything else I missed in the pattern.

@ahmed-n-abdeltwab
Copy link
Contributor

ahmed-n-abdeltwab commented Mar 6, 2026

Do you mean the typing export steps (ExtractRoutesFromAPI and declare module '@rocket.chat/rest-typings')

These are already implemented in the users file

removing the old manual typings?

yes

@krishikajain28 krishikajain28 requested a review from a team as a code owner March 7, 2026 10:00
@krishikajain28
Copy link
Author

krishikajain28 commented Mar 7, 2026

Do you mean the typing export steps (ExtractRoutesFromAPI and declare module '@rocket.chat/rest-typings')

These are already implemented in the users file

removing the old manual typings?

yes

@ahmed-n-abdeltwab I have completely removed the legacy manual typings for users.list in packages/rest-typings/src/v1/users.ts, The code is pushed and ready (I see the Dionisio bot is just waiting on the QA label/milestone) .
let me know if the code looks good to merge now, or if you need anything else from my end

url: string;
}
>;
success: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Comment on lines +762 to +763
authRequired: true,
permissionsRequired: ['view-d-room'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to stay consistent with the old API options

Comment on lines -154 to -158
'/v1/users.list': {
GET: (params: PaginatedRequest<{ fields: string }>) => PaginatedResult<{
users: DefaultUserInfo[];
}>;
};
Copy link
Contributor

@ahmed-n-abdeltwab ahmed-n-abdeltwab Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This object is separated into two sections. The first is params: PaginatedRequest<{ fields: string }>, which represents the API query or body (in your case, the query). You should use this instead of your current implementation to stay consistent with the project's codebase.

The second section is the API's return object:
PaginatedResult<{ users: DefaultUserInfo[]; }>;

We must ensure it matches this exactly because the client code expect this specific structure and it's Aline with the project pattern. Breaking changes are not acceptable. For reference, you can look at the implementations in #36916 and #36668.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

understood. I ve updated the endpoint to strictly use the PaginatedRequest and PaginatedResult<{ users: DefaultUserInfo[] }> generics to maintain the exact client server contract. I also restored queryOperations and removed the out-of-scope success additions from the schemas. lastly, I commented out the legacy ddp-client methods that were depending on the old users.list route. let me know it anything else needs adjustment

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/users.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/users.ts:787">
P1: Response schemas became inconsistent with framework helper output (`success` field), so strict AJV validation can reject valid `users.list` and `users.getAvatarSuggestion` responses.</violation>
</file>

<file name="packages/ddp-client/src/legacy/RocketchatSDKLegacy.ts">

<violation number="1" location="packages/ddp-client/src/legacy/RocketchatSDKLegacy.ts:62">
P1: `users.list` legacy helper methods were removed from the runtime `users` API, causing a breaking regression for existing `sdk.users.*` callers.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

offset: { type: 'number' },
total: { type: 'number' },
},
required: ['users', 'count', 'offset', 'total'],
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Response schemas became inconsistent with framework helper output (success field), so strict AJV validation can reject valid users.list and users.getAvatarSuggestion responses.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/api/server/v1/users.ts, line 787:

<comment>Response schemas became inconsistent with framework helper output (`success` field), so strict AJV validation can reject valid `users.list` and `users.getAvatarSuggestion` responses.</comment>

<file context>
@@ -796,20 +783,18 @@ const usersEndpoints = API.v1
-						success: { type: 'boolean', enum: [true] },
 					},
-					required: ['users', 'count', 'offset', 'total', 'success'],
+					required: ['users', 'count', 'offset', 'total'],
 					additionalProperties: false,
 				}),
</file context>
Fix with Cubic

get users() {
const self = this;
return {
/*
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: users.list legacy helper methods were removed from the runtime users API, causing a breaking regression for existing sdk.users.* callers.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ddp-client/src/legacy/RocketchatSDKLegacy.ts, line 62:

<comment>`users.list` legacy helper methods were removed from the runtime `users` API, causing a breaking regression for existing `sdk.users.*` callers.</comment>

<file context>
@@ -59,6 +59,7 @@ export class RocketchatSdkLegacyImpl extends DDPSDK implements RocketchatSDKLega
 	get users() {
 		const self = this;
 		return {
+			/*
 			all(fields?: { name: 1; username: 1; status: 1; type: 1 }): Promise<Serialized<OperationResult<'GET', '/v1/users.list'>>> {
 				return self.rest.get('/v1/users.list', { fields: JSON.stringify(fields) });
</file context>
Fix with Cubic

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/users.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/users.ts:762">
P1: `users.list` lost its unconditional `view-d-room` permission check; access is now gated only by a conditional setting, allowing broader user enumeration when that setting is off.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@krishikajain28
Copy link
Author

@ahmed-n-abdeltwab Removed success from the schema properties and deleted the permissionsRequired array to match the legacy behavior. Tested locally using CURL and it returns the expected PaginatedResult. Attached the 200 OK response.
image

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/app/api/server/v1/users.ts">

<violation number="1" location="apps/meteor/app/api/server/v1/users.ts:762">
P2: `users.list` now has an unconditional `view-d-room` gate, changing prior setting-controlled access behavior.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

{
authRequired: true,
queryOperations: ['$or', '$and'],
permissionsRequired: ['view-d-room'],
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: users.list now has an unconditional view-d-room gate, changing prior setting-controlled access behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/api/server/v1/users.ts, line 762:

<comment>`users.list` now has an unconditional `view-d-room` gate, changing prior setting-controlled access behavior.</comment>

<file context>
@@ -759,7 +759,7 @@ const usersEndpoints = API.v1
 			authRequired: true,
 			queryOperations: ['$or', '$and'],
-
+			permissionsRequired: ['view-d-room'],
 			query: ajv.compile<PaginatedRequest<{ fields?: string; query?: string }>>({
 				type: 'object',
</file context>
Fix with Cubic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't have changed this file. You should leave the endpoint definitions in rest-typings if sdkLegacy depends on them, as I previously mentioned in the chat group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants