Skip to content

Commit 07f7e1f

Browse files
feat: User phone identity lookup for external voice calls - #40680
1 parent 2bf60c2 commit 07f7e1f

3 files changed

Lines changed: 38 additions & 3 deletions

File tree

ee/packages/media-calls/src/server/CastDirector.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import type { IUser, MediaCallActor, MediaCallActorType, MediaCallContact, Media
22
import type { CallRole } from '@rocket.chat/media-signaling';
33
import { Users } from '@rocket.chat/models';
44

5+
import { BroadcastActorAgent } from './BroadcastAgent';
56
import type { IMediaCallAgent } from '../definition/IMediaCallAgent';
67
import type { IMediaCallCastDirector } from '../definition/IMediaCallCastDirector';
78
import type { GetActorContactOptions, MinimalUserData, MediaCallHeader } from '../definition/common';
89
import { UserActorAgent } from '../internal/agents/UserActorAgent';
910
import { logger } from '../logger';
10-
import { BroadcastActorAgent } from './BroadcastAgent';
1111

1212
type ContactList = Record<MediaCallActorType, MediaCallContact | null>;
1313

@@ -89,11 +89,28 @@ export class MediaCallCastDirector implements IMediaCallCastDirector {
8989

9090
const list = user
9191
? this.buildContactListForUser(user, defaultContactInfo)
92-
: this.buildContactListForExtension(sipExtension, defaultContactInfo);
92+
: await this.buildContactListForExtension(sipExtension, defaultContactInfo);
9393

9494
return this.getContactFromList(list, options);
9595
}
9696

97+
private async findUserByPhone(phoneNumber: string): Promise<Pick<IUser, '_id' | 'name' | 'username' | 'freeSwitchExtension'> | null> {
98+
const users = await Users.findByPhone<Pick<IUser, '_id' | 'name' | 'username' | 'freeSwitchExtension'>>(phoneNumber, {
99+
projection: { name: 1, username: 1, freeSwitchExtension: 1 },
100+
}).toArray();
101+
102+
if (!users.length) {
103+
return null;
104+
}
105+
106+
if (users.length > 1) {
107+
logger.warn({ msg: 'Multiple users found for phone number, identity cannot be resolved', phoneNumber });
108+
return null;
109+
}
110+
111+
return users[0];
112+
}
113+
97114
public async getAgentForActorAndRole(actor: MediaCallContact, role: CallRole): Promise<IMediaCallAgent | null> {
98115
if (actor.type === 'user') {
99116
return this.getAgentForUserActorAndRole(actor, role);
@@ -141,10 +158,17 @@ export class MediaCallCastDirector implements IMediaCallCastDirector {
141158
};
142159
}
143160

144-
protected buildContactListForExtension(sipExtension: string, defaultContactInfo?: MediaCallContactInformation): ContactList {
161+
protected async buildContactListForExtension(
162+
sipExtension: string,
163+
defaultContactInfo?: MediaCallContactInformation,
164+
): Promise<ContactList> {
165+
const user = await this.findUserByPhone(sipExtension);
166+
145167
const data: Partial<MediaCallContact> = {
146168
...defaultContactInfo,
147169
...(sipExtension && { sipExtension }),
170+
...(user?.username && { username: user.username }),
171+
...(user?.name && { displayName: user.name }),
148172
};
149173

150174
return {

packages/model-typings/src/models/IUsersModel.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ export interface IUsersModel extends IBaseModel<IUser> {
439439
findAgentsAvailableWithoutBusinessHours(userIds?: IUser['_id'][]): FindCursor<Pick<ILivechatAgent, '_id' | 'openBusinessHours'>>;
440440
updateLivechatStatusByAgentIds(userIds: string[], status: ILivechatAgentStatus): Promise<UpdateResult | Document>;
441441
findOneByFreeSwitchExtension<T extends Document = IUser>(freeSwitchExtension: string, options?: FindOptions<IUser>): Promise<T | null>;
442+
findByPhone<T extends Document = IUser>(phoneNumber: string, options?: FindOptions<IUser>): FindCursor<T>;
442443
countUsersInRoles(roles: IRole['_id'][]): Promise<number>;
443444
countAllUsersWithPendingAvatar(): Promise<number>;
444445
findOneByIdAndRole(userId: IUser['_id'], role: string, options: FindOptions<IUser>): Promise<IUser | null>;

packages/models/src/models/Users.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export class UsersRaw extends BaseRaw<IUser, DefaultFields<IUser>> implements IU
6969
{ key: { openBusinessHours: 1 }, sparse: true },
7070
{ key: { statusLivechat: 1 }, sparse: true },
7171
{ key: { freeSwitchExtension: 1 }, sparse: true, unique: true },
72+
{ key: { 'phones.number': 1 }, sparse: true },
7273
{ key: { language: 1 }, sparse: true },
7374
{ key: { 'active': 1, 'services.email2fa.enabled': 1 }, sparse: true }, // used by statistics
7475
{ key: { 'active': 1, 'services.totp.enabled': 1 }, sparse: true }, // used by statistics
@@ -2540,6 +2541,15 @@ export class UsersRaw extends BaseRaw<IUser, DefaultFields<IUser>> implements IU
25402541
);
25412542
}
25422543

2544+
findByPhone<T extends Document = IUser>(phoneNumber: string, options: FindOptions<IUser> = {}): FindCursor<T> {
2545+
return this.find<T>(
2546+
{
2547+
'phones.number': phoneNumber,
2548+
} as Filter<IUser>,
2549+
options,
2550+
);
2551+
}
2552+
25432553
// UPDATE
25442554
addImportIds(_id: IUser['_id'], importIds: string[]) {
25452555
importIds = ([] as string[]).concat(importIds);

0 commit comments

Comments
 (0)