-
Notifications
You must be signed in to change notification settings - Fork 12.6k
feat(federation): add room invites support #37532
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
690fc8f
5ce51eb
cad34e4
b5c0b10
23308f8
3889507
32b0147
c0c04d7
24b76f8
d037ff9
af68472
11ca46a
022b945
2bca9c5
d422053
5b1ba2d
e9ffadc
9981a0a
7f32615
a3e10a5
87852ca
bee3f14
a359a2d
25c197f
ec4d949
734cb26
c6c716b
045a8c2
47c27b2
b0d5af4
de4d8af
3b744e0
48bba11
612c1c8
39b5c3d
5dd716b
364eaf8
cf783b4
4f99db3
b1c1859
9ad15e5
73f8469
855618d
c4fc5d2
3e57281
9ab9491
7522d3e
ab21ff7
2433bf1
b215fbe
fc4849d
6570a83
0e6deb6
6ad7804
de16650
31021a5
b3672f6
5b2c5e5
3b03b14
fadf98c
26ea248
72fb063
f74bbb4
53bf6d8
48771b4
03677ca
7e00ab8
08e1351
cedc8bf
78f37b5
f09e1f2
ff339d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Apps, AppEvents } from '@rocket.chat/apps'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Message } from '@rocket.chat/core-services'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { IUser, IRoom, ISubscription } from '@rocket.chat/core-typings'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Subscriptions, Users } from '@rocket.chat/models'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Meteor } from 'meteor/meteor'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import { callbacks } from '../../../../lib/callbacks'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { notifyOnSubscriptionChangedById } from '../lib/notifyListener'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * Accepts a room invite when triggered by internal events such as federation | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * or third-party callbacks. Performs the necessary database updates and triggers | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * safe callbacks, ensuring no propagation loops are created during external event | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * processing. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // TODO this funcion is pretty much the same as the one in addUserToRoom.ts, we should probably | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // unify them at some point | ||||||||||||||||||||||||||||||||||||||||||||||||||
| export const performAcceptRoomInvite = async ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| room: IRoom, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| subscription: ISubscription, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| user: IUser & { username: string }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<void> => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (subscription.status !== 'INVITED' || !subscription.inviter) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-not-invited', `User was not invited to this room ${subscription.status}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const inviter = await Users.findOneById(subscription.inviter._id); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| await callbacks.run('beforeJoinRoom', user, room); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| await callbacks.run('beforeAddedToRoom', { user, inviter }, room); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await Apps.self?.triggerEvent(AppEvents.IPreRoomUserJoined, room, user, inviter); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error: any) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (error.name === AppsEngineException.name) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Meteor.Error('error-app-prevented', error.message); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| throw error; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| await Subscriptions.acceptInvitationById(subscription._id); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| void notifyOnSubscriptionChangedById(subscription._id, 'updated'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| await Message.saveSystemMessage('uj', room._id, user.username, user); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (room.t === 'c' || room.t === 'p') { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| process.nextTick(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add a new event, with an optional inviter | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await callbacks.run('afterAddedToRoom', { user, inviter }, room); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Keep the current event | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await callbacks.run('afterJoinRoom', user, room); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+50
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhandled promise rejections in deferred callbacks. The Consider wrapping the deferred logic in a try-catch: if (room.t === 'c' || room.t === 'p') {
process.nextTick(async () => {
- // Add a new event, with an optional inviter
- await callbacks.run('afterAddedToRoom', { user, inviter }, room);
-
- // Keep the current event
- await callbacks.run('afterJoinRoom', user, room);
-
- void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
+ try {
+ await callbacks.run('afterAddedToRoom', { user, inviter }, room);
+ await callbacks.run('afterJoinRoom', user, room);
+ void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
+ } catch (error) {
+ // Log error but don't propagate since this is a deferred callback
+ console.error('Error in post-join callbacks:', error);
+ }
});
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Response schema declares
voidbut returns object withsuccess.The 200 response validator (line 1087) is typed as
ajv.compile<void>but the schema defines an object with asuccessboolean property. The generic type should match the schema.📝 Committable suggestion
🤖 Prompt for AI Agents