feat: Add name overwrite API (#11543)

This commit is contained in:
Robert Pintilii 2022-05-20 11:45:09 +01:00 committed by GitHub
parent f5004a2a0c
commit 769f0a8452
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 207 additions and 7 deletions

View File

@ -40,7 +40,8 @@ import {
isParticipantModerator,
isLocalParticipantModerator,
hasRaisedHand,
grantModerator
grantModerator,
overwriteParticipantsNames
} from '../../react/features/base/participants';
import { updateSettings } from '../../react/features/base/settings';
import { isToggleCameraEnabled, toggleCamera } from '../../react/features/base/tracks';
@ -428,6 +429,11 @@ function initCommands() {
logger.error('Failed sending endpoint text message', err);
}
},
'overwrite-names': participantList => {
logger.debug('Overwrite names command received');
APP.store.dispatch(overwriteParticipantsNames(participantList));
},
'toggle-e2ee': enabled => {
logger.debug('Toggle E2EE key command received');
APP.store.dispatch(toggleE2EE(enabled));
@ -1660,6 +1666,19 @@ class API {
});
}
/**
* Notify external application that the breakout rooms changed.
*
* @param {Array} rooms - Array of breakout rooms.
* @returns {void}
*/
notifyBreakoutRoomsUpdated(rooms) {
this._sendEvent({
name: 'breakout-rooms-updated',
rooms
});
}
/**
* Disposes the allocated resources.
*

View File

@ -46,6 +46,7 @@ const commands = {
kickParticipant: 'kick-participant',
muteEveryone: 'mute-everyone',
overwriteConfig: 'overwrite-config',
overwriteNames: 'overwrite-names',
password: 'password',
pinParticipant: 'pin-participant',
rejectParticipant: 'reject-participant',
@ -94,6 +95,7 @@ const events = {
'avatar-changed': 'avatarChanged',
'audio-availability-changed': 'audioAvailabilityChanged',
'audio-mute-status-changed': 'audioMuteStatusChanged',
'breakout-rooms-updated': 'breakoutRoomsUpdated',
'browser-support': 'browserSupport',
'camera-error': 'cameraError',
'chat-updated': 'chatUpdated',

View File

@ -212,3 +212,22 @@ export const RAISE_HAND_UPDATED = 'RAISE_HAND_UPDATED';
* }
*/
export const LOCAL_PARTICIPANT_AUDIO_LEVEL_CHANGED = 'LOCAL_PARTICIPANT_AUDIO_LEVEL_CHANGED'
/**
* The type of Redux action which overwrites the name of a participant.
* {
* type: OVERWRITE_PARTICIPANT_NAME,
* id: string,
* name: string
* }
*/
export const OVERWRITE_PARTICIPANT_NAME = 'OVERWRITE_PARTICIPANT_NAME';
/**
* The type of Redux action which overwrites the names of multiple participants.
* {
* type: OVERWRITE_PARTICIPANTS_NAMES,
* participantsList: Array<Object>,
* }
*/
export const OVERWRITE_PARTICIPANTS_NAMES = 'OVERWRITE_PARTICIPANTS_NAMES';

View File

@ -18,7 +18,9 @@ import {
PIN_PARTICIPANT,
SCREENSHARE_PARTICIPANT_NAME_CHANGED,
SET_LOADABLE_AVATAR_URL,
RAISE_HAND_UPDATED
RAISE_HAND_UPDATED,
OVERWRITE_PARTICIPANT_NAME,
OVERWRITE_PARTICIPANTS_NAMES
} from './actionTypes';
import {
DISCO_REMOTE_CONTROL_FEATURE
@ -653,3 +655,31 @@ export function localParticipantAudioLevelChanged(level) {
level
};
}
/**
* Overwrites the name of the participant with the given id.
*
* @param {string} id - Participant id;.
* @param {string} name - New participant name.
* @returns {Object}
*/
export function overwriteParticipantName(id, name) {
return {
type: OVERWRITE_PARTICIPANT_NAME,
id,
name
};
}
/**
* Overwrites the names of the given participants.
*
* @param {Array<Object>} participantList - The list of participants to overwrite.
* @returns {Object}
*/
export function overwriteParticipantsNames(participantList) {
return {
type: OVERWRITE_PARTICIPANTS_NAMES,
participantList
};
}

View File

@ -5,6 +5,8 @@ import { batch } from 'react-redux';
import UIEvents from '../../../../service/UI/UIEvents';
import { approveParticipant } from '../../av-moderation/actions';
import { UPDATE_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
import { getBreakoutRooms } from '../../breakout-rooms/functions';
import { toggleE2EE } from '../../e2ee/actions';
import { MAX_MODE } from '../../e2ee/constants';
import {
@ -34,6 +36,8 @@ import {
LOCAL_PARTICIPANT_AUDIO_LEVEL_CHANGED,
LOCAL_PARTICIPANT_RAISE_HAND,
MUTE_REMOTE_PARTICIPANT,
OVERWRITE_PARTICIPANTS_NAMES,
OVERWRITE_PARTICIPANT_NAME,
PARTICIPANT_DISPLAY_NAME_CHANGED,
PARTICIPANT_JOINED,
PARTICIPANT_LEFT,
@ -44,6 +48,7 @@ import {
localParticipantIdChanged,
localParticipantJoined,
localParticipantLeft,
overwriteParticipantName,
participantLeft,
participantUpdated,
raiseHand,
@ -68,6 +73,7 @@ import {
hasRaisedHand,
isLocalParticipantModerator
} from './functions';
import logger from './logger';
import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
import './subscriber';
@ -231,6 +237,74 @@ MiddlewareRegistry.register(store => next => action => {
case PARTICIPANT_UPDATED:
return _participantJoinedOrUpdated(store, next, action);
case OVERWRITE_PARTICIPANTS_NAMES: {
const { participantList } = action;
if (!Array.isArray(participantList)) {
logger.error('Overwrite names failed. Argument is not an array.');
return;
}
batch(() => {
participantList.forEach(p => {
store.dispatch(overwriteParticipantName(p.id, p.name));
});
});
break;
}
case OVERWRITE_PARTICIPANT_NAME: {
const { dispatch, getState } = store;
const state = getState();
const { id, name } = action;
let breakoutRoom = false, identifier = id;
if (id.indexOf('@') !== -1) {
identifier = id.slice(id.indexOf('/') + 1);
breakoutRoom = true;
action.id = identifier;
}
if (breakoutRoom) {
const rooms = getBreakoutRooms(state);
const roomCounter = state['features/breakout-rooms'].roomCounter;
const newRooms = {};
Object.entries(rooms).forEach(([ key, r ]) => {
const participants = r?.participants || {};
const jid = Object.keys(participants).find(p =>
p.slice(p.indexOf('/') + 1) === identifier);
if (jid) {
newRooms[key] = {
...r,
participants: {
...participants,
[jid]: {
...participants[jid],
displayName: name
}
}
};
} else {
newRooms[key] = r;
}
});
dispatch({
type: UPDATE_BREAKOUT_ROOMS,
rooms,
roomCounter,
updatedNames: true
});
} else {
dispatch(participantUpdated({
id: identifier,
name
}));
}
break;
}
}
return next(action);
@ -491,6 +565,7 @@ function _maybePlaySounds({ getState, dispatch }, action) {
*/
function _participantJoinedOrUpdated(store, next, action) {
const { dispatch, getState } = store;
const { overwrittenNameList } = store.getState()['features/base/participants'];
const { participant: { avatarURL, email, id, local, name, raisedHandTimestamp } } = action;
// Send an external update of the local participant's raised hand state
@ -508,6 +583,10 @@ function _participantJoinedOrUpdated(store, next, action) {
}
}
if (overwrittenNameList[id]) {
action.participant.name = overwrittenNameList[id];
}
// Allow the redux update to go through and compare the old avatar
// to the new avatar and emit out change events if necessary.
const result = next(action);

View File

@ -7,6 +7,7 @@ import { ReducerRegistry, set } from '../redux';
import {
DOMINANT_SPEAKER_CHANGED,
OVERWRITE_PARTICIPANT_NAME,
PARTICIPANT_ID_CHANGED,
PARTICIPANT_JOINED,
PARTICIPANT_LEFT,
@ -63,6 +64,7 @@ const DEFAULT_STATE = {
haveParticipantWithScreenSharingFeature: false,
local: undefined,
localScreenShare: undefined,
overwrittenNameList: {},
pinnedParticipant: undefined,
raisedHandsQueue: [],
remote: new Map(),
@ -413,6 +415,17 @@ ReducerRegistry.register('features/base/participants', (state = DEFAULT_STATE, a
return { ...state };
}
case OVERWRITE_PARTICIPANT_NAME: {
const { id, name } = action;
return {
...state,
overwrittenNameList: {
...state.overwrittenNameList,
[id]: name
}
};
}
}
return state;

View File

@ -7,9 +7,10 @@ import { editMessage, MESSAGE_TYPE_REMOTE } from '../chat';
import { UPDATE_BREAKOUT_ROOMS } from './actionTypes';
import { moveToRoom } from './actions';
import { getBreakoutRooms } from './functions';
import logger from './logger';
declare var APP: Object;
/**
* Registers a change handler for state['features/base/conference'].conference to
* set the event listeners needed for the breakout rooms feature to operate.
@ -25,6 +26,9 @@ StateListenerRegistry.register(
conference.on(JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED, ({ rooms, roomCounter }) => {
logger.debug('Room list updated');
if (typeof APP !== 'undefined') {
APP.API.notifyBreakoutRoomsUpdated(rooms);
}
dispatch({
type: UPDATE_BREAKOUT_ROOMS,
rooms,
@ -36,16 +40,50 @@ StateListenerRegistry.register(
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const { type } = action;
const result = next(action);
switch (type) {
case UPDATE_BREAKOUT_ROOMS: {
const { messages } = getState()['features/chat'];
// edit name if it was overwritten
if (!action.updatedNames) {
const { overwrittenNameList } = getState()['features/base/participants'];
if (Object.keys(overwrittenNameList).length > 0) {
const newRooms = {};
Object.entries(action.rooms).forEach(([ key, r ]) => {
let participants = r?.participants || {};
let jid;
for (const id of Object.keys(overwrittenNameList)) {
jid = Object.keys(participants).find(p => p.slice(p.indexOf('/') + 1) === id);
if (jid) {
participants = {
...participants,
[jid]: {
...participants[jid],
displayName: overwrittenNameList[id]
}
};
}
}
newRooms[key] = {
...r,
participants
};
});
action.rooms = newRooms;
}
}
// edit the chat history to match names for participants in breakout rooms
const { messages } = getState()['features/chat'];
messages && messages.forEach(m => {
if (m.messageType === MESSAGE_TYPE_REMOTE && !getParticipantById(getState(), m.id)) {
const rooms = getBreakoutRooms(getState);
const rooms = action.rooms;
for (const room of Object.values(rooms)) {
// $FlowExpectedError
@ -65,5 +103,5 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
}
}
return result;
return next(action);
});