@@ -2,7 +2,7 @@ import { Apps } from '@rocket.chat/apps';
22import type { AppVideoConfProviderManager } from '@rocket.chat/apps/dist/server/managers/AppVideoConfProviderManager' ;
33import type { VideoConfData , VideoConfDataExtended } from '@rocket.chat/apps-engine/definition/videoConfProviders' ;
44import type { IVideoConfService , VideoConferenceJoinOptions } from '@rocket.chat/core-services' ;
5- import { api , ServiceClassInternal , Room } from '@rocket.chat/core-services' ;
5+ import { api , Presence , ServiceClassInternal , Room } from '@rocket.chat/core-services' ;
66import type {
77 IDirectVideoConference ,
88 ILivechatVideoConference ,
@@ -25,6 +25,7 @@ import type {
2525 IVoIPVideoConference ,
2626} from '@rocket.chat/core-typings' ;
2727import {
28+ UserStatus ,
2829 VideoConferenceStatus ,
2930 isDirectVideoConference ,
3031 isGroupVideoConference ,
@@ -322,8 +323,8 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
322323 throw new Error ( 'Invalid User' ) ;
323324 }
324325
325- const user = await Users . findOneById < Required < Pick < IUser , '_id' | 'username' | 'name' | 'avatarETag' > > > ( userId , {
326- projection : { username : 1 , name : 1 , avatarETag : 1 } ,
326+ const user = await Users . findOneById < Required < Pick < IUser , '_id' | 'username' | 'name' | 'avatarETag' | 'language' > > > ( userId , {
327+ projection : { username : 1 , name : 1 , avatarETag : 1 , language : 1 } ,
327328 } ) ;
328329 if ( ! user ) {
329330 throw new Error ( 'Invalid User' ) ;
@@ -334,6 +335,7 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
334335 username : user . username ,
335336 name : user . name ,
336337 avatarETag : user . avatarETag ,
338+ language : user . language ,
337339 ts : ts || new Date ( ) ,
338340 } ) ;
339341 }
@@ -502,6 +504,9 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
502504 }
503505
504506 await VideoConferenceModel . setDataById ( call . _id , { endedAt : new Date ( ) , status : VideoConferenceStatus . ENDED } ) ;
507+
508+ await this . clearPresenceForCall ( call ) ;
509+
505510 await this . runVideoConferenceChangedEvent ( call . _id ) ;
506511 this . notifyVideoConfUpdate ( call . rid , call . _id ) ;
507512
@@ -511,12 +516,28 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
511516 }
512517
513518 private async expireCall ( callId : VideoConference [ '_id' ] ) : Promise < void > {
514- const call = await VideoConferenceModel . findOneById < Pick < VideoConference , '_id' | 'messages' > > ( callId , { projection : { messages : 1 } } ) ;
519+ const call = await VideoConferenceModel . findOneById < Pick < VideoConference , '_id' | 'messages' | 'users' > > ( callId , {
520+ projection : { messages : 1 , users : 1 } ,
521+ } ) ;
515522 if ( ! call ) {
516523 return ;
517524 }
518525
519526 await VideoConferenceModel . setDataById ( call . _id , { endedAt : new Date ( ) , status : VideoConferenceStatus . EXPIRED } ) ;
527+
528+ await this . clearPresenceForCall ( call ) ;
529+ }
530+
531+ // clears the busy claim this conference set for each participant (id-scoped, so it never touches
532+ // a manual/calendar status or another active call a participant may hold)
533+ private async clearPresenceForCall ( call : Pick < VideoConference , '_id' | 'users' > ) : Promise < void > {
534+ await Promise . all (
535+ call . users . map ( ( user ) =>
536+ Presence . endActiveState ( user . _id , call . _id ) . catch ( ( err ) =>
537+ logger . error ( { msg : 'Failed to clear presence for user after video conference' , uid : user . _id , err } ) ,
538+ ) ,
539+ ) ,
540+ ) ;
520541 }
521542
522543 private async endDirectCall ( call : IDirectVideoConference ) : Promise < void > {
@@ -576,6 +597,10 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
576597 return message . _id ;
577598 }
578599
600+ private getLanguageForUser ( language ?: string ) : string {
601+ return language || settings . get ( 'Language' ) || 'en' ;
602+ }
603+
579604 private async validateProvider ( providerName : string ) : Promise < void > {
580605 const manager = await this . getProviderManager ( ) ;
581606 const configured = await manager . isFullyConfigured ( providerName ) . catch ( ( ) => false ) ;
@@ -1067,7 +1092,14 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
10671092
10681093 private async addUserToCall (
10691094 call : Optional < VideoConference , 'providerData' > ,
1070- { _id, username, name, avatarETag, ts } : AtLeast < Required < IUser > , '_id' | 'username' | 'name' | 'avatarETag' > & { ts ?: Date } ,
1095+ {
1096+ _id,
1097+ username,
1098+ name,
1099+ avatarETag,
1100+ language,
1101+ ts,
1102+ } : AtLeast < Required < IUser > , '_id' | 'username' | 'name' | 'avatarETag' > & { language ?: string ; ts ?: Date } ,
10711103 ) : Promise < void > {
10721104 // If the call has a discussion, ensure the user is subscribed to it;
10731105 // This is done even if the user has already joined the call before, so they can be added back if they had left the discussion.
@@ -1081,6 +1113,13 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
10811113
10821114 await VideoConferenceModel . addUserById ( call . _id , { _id, username, name, avatarETag, ts } ) ;
10831115
1116+ await Presence . setActiveState ( _id , {
1117+ statusDefault : UserStatus . BUSY ,
1118+ statusText : i18n . t ( 'Presence_status_in_a_meeting' , { lng : this . getLanguageForUser ( language ) } ) ,
1119+ statusSource : 'internal' ,
1120+ statusId : call . _id ,
1121+ } ) . catch ( ( err ) => logger . error ( { msg : 'Failed to set presence for user joining video conference' , uid : _id , err } ) ) ;
1122+
10841123 if ( call . type === 'direct' ) {
10851124 return this . updateDirectCall ( call as IDirectVideoConference , _id ) ;
10861125 }
0 commit comments