Skip to content

Conversation

@aleksandernsilva
Copy link
Contributor

@aleksandernsilva aleksandernsilva commented Dec 29, 2025

Proposed changes (including videos or screenshots)

This pull request updates the way room access is validated, particularly to improve handling of room invitations. The main focus is on allowing users with pending invitations to access rooms, and on refactoring the related logic to support this feature across the backend and frontend code.

Room Access and Invitation Handling:

  • Updated the countByRoomIdAndUserId method in the subscriptions model to accept an includeInvitations parameter, enabling the method to count both regular and invited subscriptions when specified.
  • Modified the room access validator logic in canAccessRoom.ts to use the new includeInvitations parameter, so users with invitations are now considered as having access to the room.
  • Changed the room publication method to pass includeInvitations: true when checking room access, ensuring that invited users are granted permission to access rooms.

Frontend Refactoring:

  • Refactored the useOpenRoom hook to remove direct checks for invite subscriptions, relying instead on the updated backend logic for handling invitations.

Issue(s)

FB-143

Steps to test or reproduce

  1. From Elements, invite a user from RC to a federated room
  2. On RC, access the invited room URL with embedded layout query parameter:
https://native-fed-2.qa.rocket.chat/group/room-name?layout=embedded

Further comments

Summary by CodeRabbit

  • Bug Fixes

    • Room access and permission checks now correctly consider pending invitations, preventing incorrect permission errors when opening rooms.
  • Improvements

    • Opening rooms defers subscription/permission checks until room data is loaded, reducing premature redirects or errors.
    • Invitation actions now refresh subscription state so membership updates appear immediately.
    • Live subscription updates refetch more reliably for relevant events.

✏️ Tip: You can customize this high-level summary in your review settings.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Dec 29, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Dec 29, 2025

⚠️ No Changeset found

Latest commit: 2eb0eb0

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 Dec 29, 2025

Walkthrough

Defers client-side invite subscription lookup until after room data is fetched and sanitized; threads an includeInvitations flag through server authorization and subscription counting to include invited memberships; adjusts client subscription-event refetching and invalidates subscription queries after inviting.

Changes

Cohort / File(s) Summary
Client — room opening & invitation hooks
apps/meteor/client/views/room/hooks/useOpenRoom.ts, apps/meteor/client/views/room/hooks/useRoomInvitation.tsx
Remove early invite-based RID shortcut; move dynamic imports of Rooms/Subscriptions/LegacyRoomManager later; compute sub = Subscriptions.state.find(...) after room sanitization and use it in permission/error handling; invalidate subscription query on invite success.
Client — embedded room subscription listener
apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
Broaden event filter: ignore events for different rids and 'removed' events; refetch on other matching-rid events.
Server — publications
apps/meteor/server/publications/room/index.ts
Pass includeInvitations: true to canAccessRoomAsync in getRoomByTypeAndName access check.
Server — authorization
apps/meteor/server/services/authorization/canAccessRoom.ts
Add optional { includeInvitations?: boolean } to _validateIfAlreadyJoined and forward it to subscription counting.
Model typings
packages/model-typings/src/models/ISubscriptionsModel.ts
Extend countByRoomIdAndUserId signature with optional includeInvitations?: boolean.
Models — subscriptions implementation
packages/models/src/models/Subscriptions.ts
Implement includeInvitations in countByRoomIdAndUserId; when true, include INVITED-status subscriptions in the count via an $or clause.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RoomsStore as Rooms (client)
  participant SubscriptionsStore as Subscriptions (client)
  participant Server
  participant SubscriptionsModel as Subscriptions (server/DB)

  rect rgb(220,248,235)
    Client->>RoomsStore: openRoom(rid/name)
    RoomsStore-->>Client: roomData (sanitized)
  end

  rect rgb(232,240,255)
    Client->>SubscriptionsStore: dynamic lookup (find by rid)
    SubscriptionsStore-->>Client: sub (maybe INVITED)
    Client->>Server: access check (includeInvitations if sub exists)
    Server->>SubscriptionsModel: countByRoomIdAndUserId(..., includeInvitations)
    SubscriptionsModel-->>Server: count result
    Server-->>Client: allow or NotSubscribedToRoomError / no-permission
  end

  alt legacy redirect path
    Client->>LegacyRoomManager: perform old-URL redirect using sub lookup
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • aleksandernsilva
  • sampaiodiego

Poem

🐰 I hopped through queries, waited to see,
Invites revealed after rooms came to be.
I nudged the counts to include a small nod,
Now invites are honored — hooray, little prod! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'regression: Room invited state not being displayed in embedded layout' accurately reflects the main issue being fixed and the scope of the PR addressing invitation handling in embedded layouts.
Linked Issues check ✅ Passed The PR addresses FB-143 by modifying backend and frontend logic to properly count invited subscriptions and allow access, enabling the NotSubscribedRoom invitation screen to display instead of 'Room not found' in embedded layouts.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing invitation handling: backend modifications to countByRoomIdAndUserId and canAccessRoom, and frontend refactoring of useOpenRoom and useRoomInvitation hooks to support invitation state display.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch regression/invite-embedded

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.

@codecov
Copy link

codecov bot commented Dec 29, 2025

Codecov Report

❌ Patch coverage is 87.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 70.65%. Comparing base (8928e4a) to head (2eb0eb0).
⚠️ Report is 2 commits behind head on release-8.0.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                @@
##           release-8.0.0   #38009      +/-   ##
=================================================
+ Coverage          70.60%   70.65%   +0.05%     
=================================================
  Files               3145     3145              
  Lines             108718   108726       +8     
  Branches           19534    19530       -4     
=================================================
+ Hits               76763    76825      +62     
+ Misses             29947    29901      -46     
+ Partials            2008     2000       -8     
Flag Coverage Δ
e2e 60.20% <60.00%> (+0.06%) ⬆️
e2e-api 47.45% <100.00%> (-0.04%) ⬇️
unit 71.77% <100.00%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 29, 2025

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.1GiB 1.1GiB +11MiB
rocketchat 355MiB 345MiB +11MiB
omnichannel-transcript-service 132MiB 132MiB +3.0KiB
queue-worker-service 132MiB 132MiB -129B
ddp-streamer-service 126MiB 126MiB +2.8KiB
account-service 113MiB 113MiB +2.9KiB
authorization-service 111MiB 111MiB -19KiB
presence-service 111MiB 111MiB +13KiB

📊 Historical Trend

---
config:
  theme: "dark"
  xyChart:
    width: 900
    height: 400
---
xychart
  title "Image Size Evolution by Service (Last 30 Days + This PR)"
  x-axis ["11/18 22:53", "11/19 23:02", "11/21 16:49", "11/24 17:34", "11/27 22:32", "11/28 19:05", "12/01 23:01", "12/02 21:57", "12/03 21:00", "12/04 18:17", "12/05 21:56", "12/08 20:15", "12/09 22:17", "12/10 23:26", "12/11 21:56", "12/12 22:45", "12/13 01:34", "12/15 22:31", "12/16 22:18", "12/17 21:04", "12/18 23:12", "12/19 23:27", "12/20 21:03", "12/22 18:54", "12/23 16:16", "12/24 19:38", "12/25 17:51", "12/26 13:18", "12/29 19:01", "12/30 20:52", "12/31 14:01 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12]
  line "omnichannel-transcript-service" [0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11]
  line "queue-worker-service" [0.14, 0.14, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13]
  line "rocketchat" [0.35, 0.35, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.35]
Loading

Statistics (last 30 days):

  • 📊 Average: 1.5GiB
  • ⬇️ Minimum: 1.4GiB
  • ⬆️ Maximum: 1.6GiB
  • 🎯 Current PR: 1.1GiB
ℹ️ About this report

This report compares Docker image sizes from this build against the develop baseline.

  • Tag: pr-38009
  • Baseline: develop
  • Timestamp: 2025-12-31 14:01:16 UTC
  • Historical data points: 30

Updated: Wed, 31 Dec 2025 14:01:16 GMT

@aleksandernsilva aleksandernsilva marked this pull request as ready for review December 30, 2025 19:50
@aleksandernsilva aleksandernsilva requested review from a team as code owners December 30, 2025 19:50
@aleksandernsilva aleksandernsilva added this to the 8.0.0 milestone Dec 30, 2025
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.

No issues found across 5 files

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/models/src/models/Subscriptions.ts (1)

160-170: Refactor query construction to avoid single-element $or.

When includeInvitations is false, the $or array contains only one element [{ status: { $exists: false } }], which is redundant and less efficient than adding the condition directly to the query.

🔎 Proposed refactor
 countByRoomIdAndUserId(rid: string, uid: string | undefined, includeInvitations = false): Promise<number> {
-	const query = {
+	const query: Filter<ISubscription> = {
 		rid,
 		'u._id': uid,
-		'$or': [{ status: { $exists: false } }, includeInvitations && { status: 'INVITED' as const }].filter(
-			Boolean,
-		) as Filter<ISubscription>[],
+		...(includeInvitations
+			? { $or: [{ status: { $exists: false } }, { status: 'INVITED' as const }] }
+			: { status: { $exists: false } }),
 	};

 	return this.countDocuments(query);
 }
🧹 Nitpick comments (1)
apps/meteor/client/views/room/hooks/useOpenRoom.ts (1)

61-61: Dynamic import improves code splitting.

The dynamic import of Rooms and Subscriptions stores defers loading until after room data is retrieved, improving initial bundle size. However, note that Rooms is also statically imported at line 14 (used at line 116), which partially negates this benefit.

Consider moving the line 116 usage to also use the dynamically imported Rooms:

🔎 Optional refinement

At the top of the file, remove the static import:

-import { Rooms } from '../../../stores';

Then in the error handling effect (around line 116), use dynamic import:

useEffect(() => {
	if (error) {
		if (type === 'l' && error instanceof RoomNotFoundError) {
			import('../../../stores').then(({ Rooms }) => {
				Rooms.state.remove((record) => Object.values(record).includes(reference));
			});
			queryClient.removeQueries({ queryKey: ['rooms', reference] });
			queryClient.removeQueries({ queryKey: roomsQueryKeys.info(reference) });
		}
	}
}, [error, queryClient, reference, type]);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5b23623 and 75457e2.

📒 Files selected for processing (5)
  • apps/meteor/client/views/room/hooks/useOpenRoom.ts
  • apps/meteor/server/publications/room/index.ts
  • apps/meteor/server/services/authorization/canAccessRoom.ts
  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • packages/models/src/models/Subscriptions.ts
🧰 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/server/services/authorization/canAccessRoom.ts
  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • apps/meteor/server/publications/room/index.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
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.
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
  • apps/meteor/server/publications/room/index.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
  • apps/meteor/server/publications/room/index.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.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: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • apps/meteor/server/publications/room/index.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.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/server/services/authorization/canAccessRoom.ts
  • apps/meteor/server/publications/room/index.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: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • apps/meteor/server/publications/room/index.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.ts
📚 Learning: 2025-12-09T20:01:07.355Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.ts
📚 Learning: 2025-10-27T14:38:46.994Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37303
File: apps/meteor/tests/end-to-end/api/abac.ts:1125-1137
Timestamp: 2025-10-27T14:38:46.994Z
Learning: In Rocket.Chat ABAC feature, when ABAC is disabled globally (ABAC_Enabled setting is false), room-level ABAC attributes are not evaluated when changing room types. This means converting a private room to public will succeed even if the room has ABAC attributes, as long as the global ABAC setting is disabled.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.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/server/publications/room/index.ts
  • apps/meteor/client/views/room/hooks/useOpenRoom.ts
🧬 Code graph analysis (1)
apps/meteor/server/publications/room/index.ts (1)
apps/meteor/app/authorization/server/index.ts (1)
  • canAccessRoomAsync (10-10)
⏰ 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). (2)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: 📦 Meteor Build (coverage)
🔇 Additional comments (6)
packages/model-typings/src/models/ISubscriptionsModel.ts (1)

37-37: LGTM!

The interface extension to support the optional includeInvitations parameter is correctly defined and aligns with the implementation changes in the Subscriptions model.

apps/meteor/server/publications/room/index.ts (1)

82-91: LGTM!

The addition of includeInvitations: true to the canAccessRoomAsync call correctly enables invited users to pass the room access check, addressing the core issue where invitations weren't shown in embedded layouts.

apps/meteor/server/services/authorization/canAccessRoom.ts (2)

54-58: LGTM!

The function signature extension to accept includeInvitations parameter is well-structured with proper destructuring and default values, maintaining backward compatibility.


74-74: LGTM!

The includeInvitations parameter is correctly threaded through to Subscriptions.countByRoomIdAndUserId, enabling invited users to be counted when the flag is set.

apps/meteor/client/views/room/hooks/useOpenRoom.ts (2)

77-77: Subscription lookup correctly handles invited subscriptions.

The Subscriptions.state.find lookup retrieves the subscription (including invited subscriptions) for subsequent logic checks (lines 89, 101). This works correctly with the backend changes that now allow invited users through canAccessRoomAsync.


89-91: Access control logic correctly integrates with backend changes.

This condition throws NotSubscribedToRoomError only when:

  • User exists
  • No subscription found
  • User lacks preview permission
  • Room is public

Since the backend now validates access with includeInvitations: true, invited users will have already passed validation at the publication level, ensuring this check works correctly for the invitation flow.

@aleksandernsilva aleksandernsilva marked this pull request as draft December 30, 2025 19:55
@aleksandernsilva aleksandernsilva marked this pull request as ready for review December 30, 2025 22:06
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.

No issues found across 7 files

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: 0

🧹 Nitpick comments (2)
packages/models/src/models/Subscriptions.ts (1)

160-168: LGTM! Consider extracting query construction for clarity.

The implementation correctly adds support for counting invited subscriptions. The default parameter preserves backward compatibility, and the type assertion ensures type safety.

The query construction using a ternary with spread operator is functionally correct but could be more readable if extracted into a separate variable:

const statusFilter = includeInvitations 
  ? { $or: [{ status: { $exists: false } }, { status: 'INVITED' as const }] }
  : { status: { $exists: false } };

const query = {
  rid,
  'u._id': uid,
  ...statusFilter,
};

However, this is a minor readability suggestion and not blocking.

apps/meteor/client/views/room/hooks/useRoomInvitation.tsx (1)

27-27: LGTM! Query invalidation ensures subscription data freshness.

The invalidation of subscription queries after invitation actions correctly ensures the UI reflects the updated subscription state. This is essential for the embedded layout invitation flow described in the PR objectives.

Optional: Parallel invalidation for minor performance improvement

The two invalidations could run in parallel:

await Promise.all([
  queryClient.invalidateQueries({ queryKey: roomsQueryKeys.room(room._id) }),
  queryClient.invalidateQueries({ queryKey: subscriptionsQueryKeys.subscription(room._id) }),
]);

However, the performance impact is negligible for this use case.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 75457e2 and 4cff1ad.

📒 Files selected for processing (3)
  • apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
  • apps/meteor/client/views/room/hooks/useRoomInvitation.tsx
  • packages/models/src/models/Subscriptions.ts
🧰 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/client/views/room/hooks/useRoomInvitation.tsx
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-12-09T20:01:07.355Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • apps/meteor/client/views/room/hooks/useRoomInvitation.tsx
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/client/views/room/hooks/useRoomInvitation.tsx
  • apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
📚 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: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/client/views/room/hooks/useRoomInvitation.tsx
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
📚 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: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/client/views/room/hooks/useRoomInvitation.tsx
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
🧬 Code graph analysis (1)
apps/meteor/client/views/room/hooks/useRoomInvitation.tsx (2)
packages/mock-providers/src/MockedAppRootBuilder.tsx (1)
  • queryClient (270-280)
apps/meteor/client/lib/queryKeys.ts (1)
  • subscriptionsQueryKeys (35-38)
⏰ 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). (4)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (2)
apps/meteor/client/views/room/hooks/useRoomInvitation.tsx (1)

6-6: LGTM!

Import addition is necessary for the subscription query invalidation added on line 27.

apps/meteor/client/views/room/RoomOpenerEmbedded.tsx (1)

70-76: LGTM! Simplified subscription event handling improves maintainability.

The refactored event handling correctly:

  • Filters events to only the current room's subscription
  • Ignores 'removed' events (since the subscription no longer exists)
  • Refetches subscription data for all other relevant change events

This ensures subscription state remains fresh for the embedded layout invitation flow, directly addressing the PR objectives.

ggazzo
ggazzo previously approved these changes Dec 31, 2025
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: 0

🧹 Nitpick comments (1)
apps/meteor/server/services/authorization/canAccessRoom.ts (1)

54-54: Add type annotation for the extraData parameter.

The extraData parameter lacks a type annotation, reducing type safety and IDE support. Define an interface or use the appropriate type from RoomAccessValidator.

🔎 Suggested type annotation
-async function _validateIfAlreadyJoined(room, user, extraData): Promise<boolean> {
+async function _validateIfAlreadyJoined(room, user, extraData?: { includeInvitations?: boolean }): Promise<boolean> {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4cff1ad and 2eb0eb0.

📒 Files selected for processing (1)
  • apps/meteor/server/services/authorization/canAccessRoom.ts
🧰 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/server/services/authorization/canAccessRoom.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.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/server/services/authorization/canAccessRoom.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: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.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: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.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/server/services/authorization/canAccessRoom.ts
📚 Learning: 2025-12-09T20:01:07.355Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:07.355Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • apps/meteor/server/services/authorization/canAccessRoom.ts
⏰ 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). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (2)
apps/meteor/server/services/authorization/canAccessRoom.ts (2)

70-71: Correctly passes includeInvitations parameter to subscription count method.

The countByRoomIdAndUserId method properly accepts the optional includeInvitations parameter (with default false) and uses it to determine whether to include invited subscriptions in the count query.


78-78: No changes needed. The code is correct.

ABAC and invitations are mutually exclusive by design: invite links cannot be created for ABAC-managed rooms while ABAC is enabled (only for non-ABAC-managed rooms). Since canAccessObject is only called when ABAC is enabled AND the room has abacAttributes, invited subscriptions will not exist for those rooms. Therefore, the includeInvitations flag is not applicable in the ABAC path.

@ggazzo ggazzo added the stat: QA assured Means it has been tested and approved by a company insider label Dec 31, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Dec 31, 2025
@ggazzo ggazzo merged commit b6e3a87 into release-8.0.0 Dec 31, 2025
48 checks passed
@ggazzo ggazzo deleted the regression/invite-embedded branch December 31, 2025 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants