diff --git a/react/features/base/connection/functions.js b/react/features/base/connection/functions.js index f0d30bce44..0af78aa574 100644 --- a/react/features/base/connection/functions.js +++ b/react/features/base/connection/functions.js @@ -3,6 +3,8 @@ import { toState } from '../redux'; import { toURLString } from '../util'; +import { getURLWithoutParams } from './utils'; + /** * Figures out what's the current conference URL which is supposed to indicate what conference is currently active. * When not currently in any conference and not trying to join any then 'undefined' is returned. @@ -79,56 +81,6 @@ export function isInviteURLReady(stateOrGetState: Function | Object): boolean { return Boolean(state['features/base/connection'].locationURL || state['features/base/config'].locationURL); } -/** - * Gets a {@link URL} without hash and query/search params from a specific - * {@code URL}. - * - * @param {URL} url - The {@code URL} which may have hash and query/search - * params. - * @returns {URL} - */ -export function getURLWithoutParams(url: URL): URL { - const { hash, search } = url; - - if ((hash && hash.length > 1) || (search && search.length > 1)) { - url = new URL(url.href); // eslint-disable-line no-param-reassign - url.hash = ''; - url.search = ''; - - // XXX The implementation of URL at least on React Native appends ? and - // # at the end of the href which is not desired. - let { href } = url; - - if (href) { - href.endsWith('#') && (href = href.substring(0, href.length - 1)); - href.endsWith('?') && (href = href.substring(0, href.length - 1)); - - // eslint-disable-next-line no-param-reassign - url.href === href || (url = new URL(href)); - } - } - - return url; -} - -/** - * Gets a URL string without hash and query/search params from a specific - * {@code URL}. - * - * @param {URL} url - The {@code URL} which may have hash and query/search - * params. - * @returns {string} - */ -export function getURLWithoutParamsNormalized(url: URL): string { - const urlWithoutParams = getURLWithoutParams(url).href; - - if (urlWithoutParams) { - return urlWithoutParams.toLowerCase(); - } - - return ''; -} - /** * Converts a specific id to jid if it's not jid yet. * diff --git a/react/features/base/connection/index.js b/react/features/base/connection/index.js index 8548669120..12caa6abdf 100644 --- a/react/features/base/connection/index.js +++ b/react/features/base/connection/index.js @@ -4,3 +4,4 @@ export * from './actions'; export * from './actionTypes'; export * from './constants'; export * from './functions'; +export * from './utils'; diff --git a/react/features/base/connection/utils.js b/react/features/base/connection/utils.js new file mode 100644 index 0000000000..addb00c987 --- /dev/null +++ b/react/features/base/connection/utils.js @@ -0,0 +1,51 @@ +/* @flow */ + +/** + * Gets a {@link URL} without hash and query/search params from a specific + * {@code URL}. + * + * @param {URL} url - The {@code URL} which may have hash and query/search + * params. + * @returns {URL} + */ +export function getURLWithoutParams(url: URL): URL { + const { hash, search } = url; + + if ((hash && hash.length > 1) || (search && search.length > 1)) { + url = new URL(url.href); // eslint-disable-line no-param-reassign + url.hash = ''; + url.search = ''; + + // XXX The implementation of URL at least on React Native appends ? and + // # at the end of the href which is not desired. + let { href } = url; + + if (href) { + href.endsWith('#') && (href = href.substring(0, href.length - 1)); + href.endsWith('?') && (href = href.substring(0, href.length - 1)); + + // eslint-disable-next-line no-param-reassign + url.href === href || (url = new URL(href)); + } + } + + return url; +} + +/** + * Gets a URL string without hash and query/search params from a specific + * {@code URL}. + * + * @param {URL} url - The {@code URL} which may have hash and query/search + * params. + * @returns {string} + */ +export function getURLWithoutParamsNormalized(url: URL): string { + const urlWithoutParams = getURLWithoutParams(url).href; + + if (urlWithoutParams) { + return urlWithoutParams.toLowerCase(); + } + + return ''; +} diff --git a/react/features/invite/_utils.js b/react/features/invite/_utils.js index 61967c63ff..662b9933ac 100644 --- a/react/features/invite/_utils.js +++ b/react/features/invite/_utils.js @@ -5,6 +5,9 @@ * and requires as less dependencies as possible. */ +import { getURLWithoutParams } from '../base/connection/utils'; +import { doGetJSON } from '../base/util'; + /** * Formats the conference pin in readable way for UI to display it. * Formats the pin in 3 groups of digits: @@ -26,3 +29,57 @@ export function _formatConferenceIDPin(conferenceID: Object) { conferenceIDStr.substring(partLen, 2 * partLen)} ${ conferenceIDStr.substring(2 * partLen, conferenceIDStr.length)}`; } + +/** + * Sends a GET request to obtain the conference ID necessary for identifying + * which conference to join after dialing the dial-in service. + * This function is used not only in the main app bundle but in separate bundles for the dial in numbers page, + * and we do want to limit the dependencies. + * + * @param {string} baseUrl - The url for obtaining the conference ID (pin) for + * dialing into a conference. + * @param {string} roomName - The conference name to find the associated + * conference ID. + * @param {string} mucURL - In which MUC the conference exists. + * @param {URL} url - The address we are loaded in. + * @returns {Promise} - The promise created by the request. + */ +export function getDialInConferenceID( + baseUrl: string, + roomName: string, + mucURL: string, + url: URL +): Promise { + const separator = baseUrl.includes('?') ? '&' : '?'; + const conferenceIDURL + = `${baseUrl}${separator}conference=${roomName}@${mucURL}&url=${getURLWithoutParams(url).href}`; + + return doGetJSON(conferenceIDURL, true); +} + +/** + * Sends a GET request for phone numbers used to dial into a conference. + * This function is used not only in the main app bundle but in separate bundles for the dial in numbers page, + * and we do want to limit the dependencies. + * + * @param {string} url - The service that returns conference dial-in numbers. + * @param {string} roomName - The conference name to find the associated + * conference ID. + * @param {string} mucURL - In which MUC the conference exists. + * @returns {Promise} - The promise created by the request. The returned numbers + * may be an array of Objects containing numbers, with keys countryCode, + * tollFree, formattedNumber or an object with countries as keys and arrays of + * phone number strings, as the second one should not be used and is deprecated. + */ +export function getDialInNumbers( + url: string, + roomName: string, + mucURL: string +): Promise<*> { + const separator = url.includes('?') ? '&' : '?'; + + // when roomName and mucURL are available + // provide conference when looking up dial in numbers + + return doGetJSON(url + (roomName && mucURL ? `${separator}conference=${roomName}@${mucURL}` : ''), true); +} diff --git a/react/features/invite/actions.any.js b/react/features/invite/actions.any.js index d26301b424..3883a9987e 100644 --- a/react/features/invite/actions.any.js +++ b/react/features/invite/actions.any.js @@ -6,6 +6,7 @@ import { getInviteURL } from '../base/connection'; import { getLocalParticipant, getParticipantCount } from '../base/participants'; import { inviteVideoRooms } from '../videosipgw'; +import { getDialInConferenceID, getDialInNumbers } from './_utils'; import { ADD_PENDING_INVITE_REQUEST, BEGIN_ADD_PEOPLE, @@ -17,8 +18,6 @@ import { } from './actionTypes'; import { INVITE_TYPES } from './constants'; import { - getDialInConferenceID, - getDialInNumbers, invitePeopleAndChatRooms, inviteSipEndpoints } from './functions'; @@ -209,11 +208,12 @@ export function updateDialInNumbers() { return; } + const { locationURL = {} } = state['features/base/connection']; const { room } = state['features/base/conference']; Promise.all([ getDialInNumbers(dialInNumbersUrl, room, mucURL), - getDialInConferenceID(dialInConfCodeUrl, room, mucURL) + getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL) ]) .then(([ dialInNumbers, { conference, id, message, sipUri } ]) => { if (!conference || !id) { diff --git a/react/features/invite/components/dial-in-info-page/DialInInfoApp.web.js b/react/features/invite/components/dial-in-info-page/DialInInfoApp.web.js index a61101e101..0e5a85dd92 100644 --- a/react/features/invite/components/dial-in-info-page/DialInInfoApp.web.js +++ b/react/features/invite/components/dial-in-info-page/DialInInfoApp.web.js @@ -5,12 +5,16 @@ import { I18nextProvider } from 'react-i18next'; import { isMobileBrowser } from '../../../base/environment/utils'; import { i18next } from '../../../base/i18n'; import { parseURLParams } from '../../../base/util/parseURLParams'; +import { DIAL_IN_INFO_PAGE_PATH_NAME } from '../../constants'; import { DialInSummary } from '../dial-in-summary'; import NoRoomError from './NoRoomError'; document.addEventListener('DOMContentLoaded', () => { const { room } = parseURLParams(window.location, true, 'search'); + const { href } = window.location; + const ix = href.indexOf(DIAL_IN_INFO_PAGE_PATH_NAME); + const url = (ix > 0 ? href.substring(0, ix) : href) + room; ReactDOM.render( @@ -18,7 +22,8 @@ document.addEventListener('DOMContentLoaded', () => { ? + room = { decodeURIComponent(room) } + url = { url } /> : } , document.getElementById('react') diff --git a/react/features/invite/components/dial-in-summary/web/DialInSummary.js b/react/features/invite/components/dial-in-summary/web/DialInSummary.js index d30a422bba..ad39cd082e 100644 --- a/react/features/invite/components/dial-in-summary/web/DialInSummary.js +++ b/react/features/invite/components/dial-in-summary/web/DialInSummary.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import { translate } from '../../../../base/i18n'; -import { doGetJSON } from '../../../../base/util'; +import { getDialInConferenceID, getDialInNumbers } from '../../../_utils'; import ConferenceID from './ConferenceID'; import NumbersList from './NumbersList'; @@ -30,6 +30,11 @@ type Props = { */ room: string, + /** + * The url where we were loaded. + */ + url: string, + /** * Invoked to obtain translated strings. */ @@ -177,7 +182,7 @@ class DialInSummary extends Component { return Promise.resolve(); } - return doGetJSON(`${dialInConfCodeUrl}?conference=${room}@${mucURL}`, true) + return getDialInConferenceID(dialInConfCodeUrl, room, mucURL, new URL(this.props.url)) .catch(() => Promise.reject(this.props.t('info.genericError'))); } @@ -191,20 +196,12 @@ class DialInSummary extends Component { const { room } = this.props; const { dialInNumbersUrl, hosts } = config; const mucURL = hosts && hosts.muc; - let URLSuffix = ''; if (!dialInNumbersUrl) { return Promise.reject(this.props.t('info.dialInNotSupported')); } - // when room and mucURL are available - // provide conference when looking up dial in numbers - - if (room && mucURL) { - URLSuffix = `?conference=${room}@${mucURL}`; - } - - return doGetJSON(`${dialInNumbersUrl}${URLSuffix}`, true) + return getDialInNumbers(dialInNumbersUrl, room, mucURL) .catch(() => Promise.reject(this.props.t('info.genericError'))); } diff --git a/react/features/invite/constants.js b/react/features/invite/constants.js index a2f8a31678..e3c03d0c06 100644 --- a/react/features/invite/constants.js +++ b/react/features/invite/constants.js @@ -1,5 +1,12 @@ // @flow +/** + * The pathName for the dialInInfo page. + * + * @type {string} + */ +export const DIAL_IN_INFO_PAGE_PATH_NAME = 'static/dialInInfo.html'; + /** * Modal ID for the DialInSummary modal. */ diff --git a/react/features/invite/functions.js b/react/features/invite/functions.js index 6c8965c812..f257bbcc85 100644 --- a/react/features/invite/functions.js +++ b/react/features/invite/functions.js @@ -8,10 +8,15 @@ import { i18next } from '../base/i18n'; import { JitsiRecordingConstants } from '../base/lib-jitsi-meet'; import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants'; import { toState } from '../base/redux'; -import { doGetJSON, parseURIString } from '../base/util'; +import { parseURIString } from '../base/util'; import { isVpaasMeeting } from '../jaas/functions'; -import { INVITE_TYPES, SIP_ADDRESS_REGEX } from './constants'; +import { getDialInConferenceID, getDialInNumbers } from './_utils'; +import { + DIAL_IN_INFO_PAGE_PATH_NAME, + INVITE_TYPES, + SIP_ADDRESS_REGEX +} from './constants'; import logger from './logger'; declare var $: Function; @@ -37,51 +42,6 @@ export function checkDialNumber( }); } -/** - * Sends a GET request to obtain the conference ID necessary for identifying - * which conference to join after diaing the dial-in service. - * - * @param {string} baseUrl - The url for obtaining the conference ID (pin) for - * dialing into a conference. - * @param {string} roomName - The conference name to find the associated - * conference ID. - * @param {string} mucURL - In which MUC the conference exists. - * @returns {Promise} - The promise created by the request. - */ -export function getDialInConferenceID( - baseUrl: string, - roomName: string, - mucURL: string -): Promise { - - const conferenceIDURL = `${baseUrl}?conference=${roomName}@${mucURL}`; - - return doGetJSON(conferenceIDURL, true); -} - -/** - * Sends a GET request for phone numbers used to dial into a conference. - * - * @param {string} url - The service that returns conference dial-in numbers. - * @param {string} roomName - The conference name to find the associated - * conference ID. - * @param {string} mucURL - In which MUC the conference exists. - * @returns {Promise} - The promise created by the request. The returned numbers - * may be an array of Objects containing numbers, with keys countryCode, - * tollFree, formattedNumber or an object with countries as keys and arrays of - * phone number strings, as the second one should not be used and is deprecated. - */ -export function getDialInNumbers( - url: string, - roomName: string, - mucURL: string -): Promise<*> { - - const fullUrl = `${url}?conference=${roomName}@${mucURL}`; - - return doGetJSON(fullUrl, true); -} - /** * Removes all non-numeric characters from a string. * @@ -564,6 +524,7 @@ export function getShareInfoText( // in the state const { dialInConfCodeUrl, dialInNumbersUrl, hosts } = state['features/base/config']; + const { locationURL = {} } = state['features/base/connection']; const mucURL = hosts && hosts.muc; if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) { @@ -573,7 +534,7 @@ export function getShareInfoText( numbersPromise = Promise.all([ getDialInNumbers(dialInNumbersUrl, room, mucURL), - getDialInConferenceID(dialInConfCodeUrl, room, mucURL) + getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL) ]).then(([ numbers, { conference, id, message } ]) => { @@ -633,7 +594,7 @@ export function getDialInfoPageURL(state: Object, roomName: ?string) { const { href } = locationURL; const room = _decodeRoomURI(conferenceName); - const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/static/dialInInfo.html`; + const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/${DIAL_IN_INFO_PAGE_PATH_NAME}`; return `${url}?room=${room}`; } @@ -651,7 +612,7 @@ export function getDialInfoPageURLForURIString( } const { protocol, host, contextRoot, room } = parseURIString(uri); - return `${protocol}//${host}${contextRoot}static/dialInInfo.html?room=${room}`; + return `${protocol}//${host}${contextRoot}${DIAL_IN_INFO_PAGE_PATH_NAME}?room=${room}`; } /**