From 50f47961440c5784e3891b79fa010c77a3cfc5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 12 Nov 2019 13:37:54 +0000 Subject: [PATCH] Adds an option to set email through iframe API init and to stats. (#4842) * Adds an option to set email through iframe API init and to stats. * Simplifies configuring email and displayName in stats. Removes enableStatsID as not needed as when off we are sending as callstats id xmpp resource which is unique per call and id must be something that sticks between calls (callstatsUsername). * Adds email and displayName in stats config for mobile. * chore(deps): Updates lib-jitsi-meet to latest dd31f0a. * Removes enableStatsID from config and whitelist. --- conference.js | 10 ++++-- config.js | 6 ++-- doc/api.md | 14 ++++++++ modules/API/external/external_api.js | 8 +++-- package-lock.json | 4 +-- package.json | 2 +- react/features/base/conference/actions.js | 9 +++-- react/features/base/config/configWhitelist.js | 2 +- react/features/base/settings/middleware.js | 33 +++++++++++++++++++ react/features/base/util/uri.js | 2 +- 10 files changed, 74 insertions(+), 16 deletions(-) diff --git a/conference.js b/conference.js index be0e33947..95273f5b7 100644 --- a/conference.js +++ b/conference.js @@ -1205,12 +1205,16 @@ export default { _getConferenceOptions() { const options = config; + const { email, name: nick } = getLocalParticipant(APP.store.getState()); - const nick = APP.store.getState()['features/base/settings'].displayName; const { locationURL } = APP.store.getState()['features/base/connection']; - if (nick) { - options.displayName = nick; + if (options.enableDisplayNameInStats && nick) { + options.statisticsDisplayName = nick; + } + + if (options.enableEmailInStats && email) { + options.statisticsId = email; } options.applicationName = interfaceConfig.APP_NAME; diff --git a/config.js b/config.js index 33f70d04d..52dee5f70 100644 --- a/config.js +++ b/config.js @@ -292,13 +292,11 @@ var config = { // callStatsID: '', // callStatsSecret: '', - // enables callstatsUsername to be reported as statsId and used - // by callstats as repoted remote id - // enableStatsID: false - // enables sending participants display name to callstats // enableDisplayNameInStats: false + // enables sending participants email if available to callstats and other analytics + // enableEmailInStats: false // Privacy // diff --git a/doc/api.md b/doc/api.md index 06c36dce3..bea898d9a 100644 --- a/doc/api.md +++ b/doc/api.md @@ -30,6 +30,7 @@ Its constructor gets a number of options: * **onload**: (optional) handler for the iframe onload event. * **invitees**: (optional) Array of objects containing information about new participants that will be invited in the call. * **devices**: (optional) A map containing information about the initial devices that will be used in the call. + * **userInfo**: (optional) JS object containing information about the participant opening the meeting, such as `email`. Example: @@ -84,6 +85,19 @@ const options = { const api = new JitsiMeetExternalAPI(domain, options); ``` +You can set the userInfo(email) for the call: + +```javascript +var domain = "meet.jit.si"; +var options = { + ... + userInfo: { + email: 'email@jitsiexamplemail.com' + } +} +var api = new JitsiMeetExternalAPI(domain, options); +``` + ### Controlling the embedded Jitsi Meet Conference Device management `JitsiMeetExternalAPI` methods: diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 67946ef04..aadf4ca74 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -232,6 +232,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter { * information about new participants that will be invited in the call. * @param {Array} [options.devices] - Array of objects containing * information about the initial devices that will be used in the call. + * @param {Object} [options.userInfo] - Object containing information about + * the participant opening the meeting. */ constructor(domain, ...args) { super(); @@ -246,7 +248,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter { jwt = undefined, onload = undefined, invitees, - devices + devices, + userInfo } = parseArguments(args); this._parentNode = parentNode; @@ -256,7 +259,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter { jwt, noSSL, roomName, - devices + devices, + userInfo }); this._createIFrame(height, width, onload); this._transport = new Transport({ diff --git a/package-lock.json b/package-lock.json index b01b1f451..726f055e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10931,8 +10931,8 @@ } }, "lib-jitsi-meet": { - "version": "github:jitsi/lib-jitsi-meet#1de69abe22aa632c9a4255ee9f6ae48dab9be756", - "from": "github:jitsi/lib-jitsi-meet#1de69abe22aa632c9a4255ee9f6ae48dab9be756", + "version": "github:jitsi/lib-jitsi-meet#dd31f0aff0a38b3cfd8e808e457a2e3a0f966514", + "from": "github:jitsi/lib-jitsi-meet#dd31f0aff0a38b3cfd8e808e457a2e3a0f966514", "requires": { "@jitsi/sdp-interop": "0.1.14", "@jitsi/sdp-simulcast": "0.2.2", diff --git a/package.json b/package.json index 536ce7f27..b91383e28 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "js-utils": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31", "jsrsasign": "8.0.12", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#1de69abe22aa632c9a4255ee9f6ae48dab9be756", + "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#dd31f0aff0a38b3cfd8e808e457a2e3a0f966514", "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d", "lodash": "4.17.13", "moment": "2.19.4", diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index c99c68944..9b809d89f 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -14,6 +14,7 @@ import { JitsiConferenceEvents } from '../lib-jitsi-meet'; import { setAudioMuted, setVideoMuted } from '../media'; import { dominantSpeakerChanged, + getLocalParticipant, getNormalizedDisplayName, participantConnectionStatusChanged, participantKicked, @@ -393,14 +394,18 @@ export function createConference() { throw new Error('Cannot join a conference without a room name!'); } + const config = state['features/base/config']; + const { email, name: nick } = getLocalParticipant(state); const conference = connection.initJitsiConference( getBackendSafeRoomName(room), { - ...state['features/base/config'], + ...config, applicationName: getName(), getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats, - confID: `${locationURL.host}${locationURL.pathname}` + confID: `${locationURL.host}${locationURL.pathname}`, + statisticsDisplayName: config.enableDisplayNameInStats ? nick : undefined, + statisticsId: config.enableEmailInStats ? email : undefined }); connection[JITSI_CONNECTION_CONFERENCE_KEY] = conference; diff --git a/react/features/base/config/configWhitelist.js b/react/features/base/config/configWhitelist.js index 50b8cece4..94bd824f6 100644 --- a/react/features/base/config/configWhitelist.js +++ b/react/features/base/config/configWhitelist.js @@ -91,11 +91,11 @@ export default [ 'displayJids', 'e2eping', 'enableDisplayNameInStats', + 'enableEmailInStats', 'enableLayerSuspension', 'enableLipSync', 'disableLocalVideoFlip', 'enableRemb', - 'enableStatsID', 'enableTalkWhileMuted', 'enableTcc', 'etherpad_base', diff --git a/react/features/base/settings/middleware.js b/react/features/base/settings/middleware.js index dd2637bcb..890b77b92 100644 --- a/react/features/base/settings/middleware.js +++ b/react/features/base/settings/middleware.js @@ -1,7 +1,10 @@ // @flow +import _ from 'lodash'; import { APP_WILL_MOUNT } from '../app'; import { setAudioOnly } from '../audio-only'; +import parseURLParams from '../config/parseURLParams'; // minimize imports to avoid circular imports +import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports import { getLocalParticipant, participantUpdated } from '../participants'; import { MiddlewareRegistry } from '../redux'; @@ -28,6 +31,9 @@ MiddlewareRegistry.register(store => next => action => { _maybeSetAudioOnly(store, action); _updateLocalParticipant(store, action); break; + case SET_LOCATION_URL: + _updateLocalParticipantFromUrl(store); + break; } return result; @@ -118,3 +124,30 @@ function _updateLocalParticipant({ dispatch, getState }, action) { dispatch(participantUpdated(newLocalParticipant)); } + + +/** + * Returns the userInfo set in the URL. + * + * @param {Store} store - The redux store. + * @private + * @returns {void} + */ +function _updateLocalParticipantFromUrl({ dispatch, getState }) { + const urlParams + = parseURLParams(getState()['features/base/connection'].locationURL); + const urlEmail = urlParams['userInfo.email']; + + if (!urlEmail) { + return; + } + + const localParticipant = getLocalParticipant(getState()); + + if (localParticipant) { + dispatch(participantUpdated({ + ...localParticipant, + email: _.escape(urlEmail) + })); + } +} diff --git a/react/features/base/util/uri.js b/react/features/base/util/uri.js index e114adcb1..b7459a727 100644 --- a/react/features/base/util/uri.js +++ b/react/features/base/util/uri.js @@ -510,7 +510,7 @@ export function urlObjectToString(o: Object): ?string { let { hash } = url; - for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices' ]) { + for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices', 'userInfo' ]) { const urlParamsArray = _objectToURLParamsArray( o[`${urlPrefix}Overwrite`]