Coding style/naming: invite & invitee(s)

Hristo Terezov, Chris Cordle, and I/Lyubomir Marinov agreed that we'd
try to use "invite" & "invitee(s)" in Web/React's iframe API,
mobile/react-native's SDK invite API, and internally for the purposes of
consistency, ease of understanding, etc.
pull/2911/head jitsi-meet_3015
Lyubo Marinov 7 years ago committed by Saúl Ibarra Corretgé
parent 69eefc82a5
commit 520bb8bd22
  1. 23
      modules/API/API.js
  2. 155
      react/features/invite/actions.js
  3. 31
      react/features/invite/components/AddPeopleDialog.web.js
  4. 120
      react/features/invite/functions.js
  5. 7
      react/features/invite/middleware.native.js

@ -1,12 +1,12 @@
// @flow
import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
import {
createApiEvent,
sendAnalytics
} from '../../react/features/analytics';
import { sendInvitesForItems } from '../../react/features/invite';
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
import { invite } from '../../react/features/invite';
import { getJitsiMeetTransport } from '../transport';
import { API_ID } from './constants';
@ -114,15 +114,20 @@ function initCommands() {
switch (name) {
case 'invite':
APP.store.dispatch(
sendInvitesForItems(request.invitees))
.then(failedInvites => {
const failed = failedInvites.length === 0;
invite(request.invitees))
.then(failedInvitees => {
let error;
let result;
if (failedInvitees.length) {
error = new Error('One or more invites failed!');
} else {
result = true;
}
callback({
result: failed ? undefined : true,
error: failed
? new Error('One or more invites failed!')
: undefined
error,
result
});
});
break;

@ -33,66 +33,25 @@ export function beginAddPeople() {
}
/**
* Sends AJAX requests for dial-in numbers and conference ID.
*
* @returns {Function}
*/
export function updateDialInNumbers() {
return (dispatch: Dispatch<*>, getState: Function) => {
const state = getState();
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
= state['features/base/config'];
const mucURL = hosts && hosts.muc;
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
// URLs for fetching dial in numbers not defined
return;
}
const { room } = state['features/base/conference'];
Promise.all([
getDialInNumbers(dialInNumbersUrl),
getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
])
.then(([ dialInNumbers, { conference, id, message } ]) => {
if (!conference || !id) {
return Promise.reject(message);
}
dispatch({
type: UPDATE_DIAL_IN_NUMBERS_SUCCESS,
conferenceID: id,
dialInNumbers
});
})
.catch(error => {
dispatch({
type: UPDATE_DIAL_IN_NUMBERS_FAILED,
error
});
});
};
}
/**
* Send invites for a list of items (may be a combination of users, rooms, phone
* numbers, and video rooms).
* Invites (i.e. sends invites to) an array of invitees (which may be a
* combination of users, rooms, phone numbers, and video rooms).
*
* @param {Array<Object>} invites - Items for which invites should be sent.
* @returns {Promise} Promise containing the list of invites that were not sent.
* @param {Array<Object>} invitees - The recepients to send invites to.
* @returns {Promise<Array<Object>>} A {@code Promise} resolving with an array
* of invitees who were not invited (i.e. invites were not sent to them).
*/
export function sendInvitesForItems(invites: Array<Object>) {
export function invite(invitees: Array<Object>) {
return (
dispatch: Dispatch<*>,
getState: Function): Promise<Array<Object>> => {
let allInvitePromises = [];
let invitesLeftToSend = [ ...invites ];
let invitesLeftToSend = [ ...invitees ];
const state = getState();
const { conference } = state['features/base/conference'];
const { inviteServiceUrl } = state['features/base/config'];
const inviteUrl = getInviteURL(state);
const jwt = state['features/base/jwt'].jwt;
const { jwt } = state['features/base/jwt'];
// First create all promises for dialing out.
if (conference) {
@ -105,54 +64,98 @@ export function sendInvitesForItems(invites: Array<Object>) {
const numberToInvite = getDigitsOnly(item.number);
return conference.dial(numberToInvite)
.then(() => {
invitesLeftToSend
= invitesLeftToSend.filter(invite =>
invite !== item);
})
.catch(error => logger.error(
'Error inviting phone number:', error));
.then(() => {
invitesLeftToSend
= invitesLeftToSend.filter(
invitee => invitee !== item);
})
.catch(error =>
logger.error('Error inviting phone number:', error));
});
allInvitePromises = allInvitePromises.concat(phoneInvitePromises);
}
const usersAndRooms = invitesLeftToSend.filter(item =>
item.type === 'user' || item.type === 'room');
const usersAndRooms
= invitesLeftToSend.filter(
({ type }) => type === 'user' || type === 'room');
if (usersAndRooms.length) {
// Send a request to invite all the rooms and users. On success,
// filter all rooms and users from {@link invitesLeftToSend}.
const peopleInvitePromise = invitePeopleAndChatRooms(
inviteServiceUrl,
inviteUrl,
jwt,
usersAndRooms)
const peopleInvitePromise
= invitePeopleAndChatRooms(
inviteServiceUrl,
inviteUrl,
jwt,
usersAndRooms)
.then(() => {
invitesLeftToSend = invitesLeftToSend.filter(item =>
item.type !== 'user' && item.type !== 'room');
invitesLeftToSend
= invitesLeftToSend.filter(
({ type }) => type !== 'user' && type !== 'room');
})
.catch(error => logger.error(
'Error inviting people:', error));
.catch(error => logger.error('Error inviting people:', error));
allInvitePromises.push(peopleInvitePromise);
}
// Sipgw calls are fire and forget. Invite them to the conference
// then immediately remove them from {@link invitesLeftToSend}.
const vrooms = invitesLeftToSend.filter(item =>
item.type === 'videosipgw');
// Sipgw calls are fire and forget. Invite them to the conference, then
// immediately remove them from invitesLeftToSend.
const vrooms
= invitesLeftToSend.filter(({ type }) => type === 'videosipgw');
conference
&& vrooms.length > 0
&& dispatch(inviteVideoRooms(conference, vrooms));
invitesLeftToSend = invitesLeftToSend.filter(item =>
item.type !== 'videosipgw');
invitesLeftToSend
= invitesLeftToSend.filter(({ type }) => type !== 'videosipgw');
return (
Promise.all(allInvitePromises)
.then(() => invitesLeftToSend)
);
.then(() => invitesLeftToSend));
};
}
/**
* Sends AJAX requests for dial-in numbers and conference ID.
*
* @returns {Function}
*/
export function updateDialInNumbers() {
return (dispatch: Dispatch<*>, getState: Function) => {
const state = getState();
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
= state['features/base/config'];
const mucURL = hosts && hosts.muc;
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
// URLs for fetching dial in numbers not defined
return;
}
const { room } = state['features/base/conference'];
Promise.all([
getDialInNumbers(dialInNumbersUrl),
getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
])
.then(([ dialInNumbers, { conference, id, message } ]) => {
if (!conference || !id) {
return Promise.reject(message);
}
dispatch({
type: UPDATE_DIAL_IN_NUMBERS_SUCCESS,
conferenceID: id,
dialInNumbers
});
})
.catch(error => {
dispatch({
type: UPDATE_DIAL_IN_NUMBERS_FAILED,
error
});
});
};
}

@ -11,11 +11,8 @@ import { Dialog, hideDialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
import { MultiSelectAutocomplete } from '../../base/react';
import {
getInviteResultsForQuery,
getInviteTypeCounts
} from '../functions';
import { sendInvitesForItems } from '../actions';
import { invite } from '../actions';
import { getInviteResultsForQuery, getInviteTypeCounts } from '../functions';
const logger = require('jitsi-meet-logger').getLogger(__filename);
@ -68,7 +65,7 @@ class AddPeopleDialog extends Component<*, *> {
dialOutEnabled: PropTypes.bool,
/**
* The redux dispatch method.
* The redux {@code dispatch} function.
*/
dispatch: PropTypes.func,
@ -282,8 +279,8 @@ class AddPeopleDialog extends Component<*, *> {
*/
_onSubmit() {
const { inviteItems } = this.state;
const items = inviteItems.map(item => item.item);
const inviteTypeCounts = getInviteTypeCounts(items);
const invitees = inviteItems.map(({ item }) => item);
const inviteTypeCounts = getInviteTypeCounts(invitees);
sendAnalytics(createInviteDialogEvent(
'clicked', 'inviteButton', {
@ -301,7 +298,7 @@ class AddPeopleDialog extends Component<*, *> {
const { dispatch } = this.props;
dispatch(sendInvitesForItems(items))
dispatch(invite(invitees))
.then(invitesLeftToSend => {
// If any invites are left that means something failed to send
// so treat it as an error.
@ -322,15 +319,12 @@ class AddPeopleDialog extends Component<*, *> {
addToCallError: true
});
const unsentInviteIDs = invitesLeftToSend.map(invite =>
invite.id || invite.number
);
const itemsToSelect = inviteItems.filter(invite =>
unsentInviteIDs.includes(
invite.item.id || invite.item.number
)
);
const unsentInviteIDs
= invitesLeftToSend.map(invitee =>
invitee.id || invitee.number);
const itemsToSelect
= inviteItems.filter(({ item }) =>
unsentInviteIDs.includes(item.id || item.number));
if (this._multiselect) {
this._multiselect.setSelectedItems(itemsToSelect);
@ -431,7 +425,6 @@ class AddPeopleDialog extends Component<*, *> {
_peopleSearchQueryTypes,
_peopleSearchUrl
} = this.props;
const options = {
dialOutAuthUrl: _dialOutAuthUrl,
addPeopleEnabled,

@ -76,9 +76,8 @@ export function getDialInNumbers(url: string): Promise<*> {
/**
* Removes all non-numeric characters from a string.
*
* @param {string} text - The string from which to remove all characters
* except numbers.
* @private
* @param {string} text - The string from which to remove all characters except
* numbers.
* @returns {string} A string with only numbers.
*/
export function getDigitsOnly(text: string = ''): string {
@ -126,8 +125,8 @@ export type GetInviteResultsOptions = {
* Combines directory search with phone number validation to produce a single
* set of invite search results.
*
* @param {string} query - Text to search.
* @param {GetInviteResultsOptions} options - Options to use when searching.
* @param {string} query - Text to search.
* @param {GetInviteResultsOptions} options - Options to use when searching.
* @returns {Promise<*>}
*/
export function getInviteResultsForQuery(
@ -166,19 +165,18 @@ export function getInviteResultsForQuery(
let numberToVerify = text;
// When the number to verify does not start with a +, we assume no
// proper country code has been entered. In such a case, prepend 1
// for the country code. The service currently takes care of
// prepending the +.
// proper country code has been entered. In such a case, prepend 1 for
// the country code. The service currently takes care of prepending the
// +.
if (!hasCountryCode && !text.startsWith('1')) {
numberToVerify = `1${numberToVerify}`;
}
// The validation service works properly when the query is digits
// only so ensure only digits get sent.
// The validation service works properly when the query is digits only
// so ensure only digits get sent.
numberToVerify = getDigitsOnly(numberToVerify);
phoneNumberPromise
= checkDialNumber(numberToVerify, dialOutAuthUrl);
phoneNumberPromise = checkDialNumber(numberToVerify, dialOutAuthUrl);
} else {
phoneNumberPromise = Promise.resolve({});
}
@ -190,18 +188,16 @@ export function getInviteResultsForQuery(
];
/**
* This check for phone results is for the day the call to
* searching people might return phone results as well. When
* that day comes this check will make it so the server checks
* are honored and the local appending of the number is not
* done. The local appending of the phone number can then be
* cleaned up when convenient.
* This check for phone results is for the day the call to searching
* people might return phone results as well. When that day comes
* this check will make it so the server checks are honored and the
* local appending of the number is not done. The local appending of
* the phone number can then be cleaned up when convenient.
*/
const hasPhoneResult = peopleResults.find(
result => result.type === 'phone');
const hasPhoneResult
= peopleResults.find(result => result.type === 'phone');
if (!hasPhoneResult
&& typeof phoneResults.allow === 'boolean') {
if (!hasPhoneResult && typeof phoneResults.allow === 'boolean') {
results.push({
allowed: phoneResults.allow,
country: phoneResults.country,
@ -216,6 +212,28 @@ export function getInviteResultsForQuery(
});
}
/**
* Helper for determining how many of each type of user is being invited. Used
* for logging and sending analytics related to invites.
*
* @param {Array} inviteItems - An array with the invite items, as created in
* {@link _parseQueryResults}.
* @returns {Object} An object with keys as user types and values as the number
* of invites for that type.
*/
export function getInviteTypeCounts(inviteItems: Array<Object> = []) {
const inviteTypeCounts = {};
inviteItems.forEach(({ type }) => {
if (!inviteTypeCounts[type]) {
inviteTypeCounts[type] = 0;
}
inviteTypeCounts[type]++;
});
return inviteTypeCounts;
}
/**
* Sends a post request to an invite service.
*
@ -223,8 +241,8 @@ export function getInviteResultsForQuery(
* invitation.
* @param {string} inviteUrl - The url to the conference.
* @param {string} jwt - The jwt token to pass to the search service.
* @param {Immutable.List} inviteItems - The list of the "user" or "room"
* type items to invite.
* @param {Immutable.List} inviteItems - The list of the "user" or "room" type
* items to invite.
* @returns {Promise} - The promise created by the request.
*/
export function invitePeopleAndChatRooms( // eslint-disable-line max-params
@ -282,24 +300,37 @@ export function isAddPeopleEnabled(state: Object): boolean {
* @returns {boolean} Indication of whether dial out is currently enabled.
*/
export function isDialOutEnabled(state: Object): boolean {
const participant = getLocalParticipant(state);
const { conference } = state['features/base/conference'];
const { isGuest } = state['features/base/jwt'];
const { enableUserRolesBasedOnToken } = state['features/base/config'];
const participant = getLocalParticipant(state);
let dialOutEnabled
= participant && participant.role === PARTICIPANT_ROLE.MODERATOR
&& conference && conference.isSIPCallingSupported()
&& (!enableUserRolesBasedOnToken || !isGuest);
if (dialOutEnabled) {
// XXX The mobile/react-native app is capable of disabling of dial-out.
// Anyway, the Web/React app does not have that capability so default
// appropriately.
const { app } = state['features/app'];
dialOutEnabled = app && app.props.dialoOutEnabled;
return (
(typeof dialOutEnabled === 'undefined') || Boolean(dialOutEnabled));
}
return participant && participant.role === PARTICIPANT_ROLE.MODERATOR
&& conference && conference.isSIPCallingSupported()
&& (!enableUserRolesBasedOnToken || !isGuest);
return false;
}
/**
* Checks whether a string looks like it could be for a phone number.
*
* @param {string} text - The text to check whether or not it could be a
* phone number.
* @private
* @returns {boolean} True if the string looks like it could be a phone
* @param {string} text - The text to check whether or not it could be a phone
* number.
* @private
* @returns {boolean} True if the string looks like it could be a phone number.
*/
function isMaybeAPhoneNumber(text: string): boolean {
if (!isPhoneNumberRegex().test(text)) {
@ -365,28 +396,3 @@ export function searchDirectory( // eslint-disable-line max-params
return Promise.reject(error);
});
}
/**
* Helper for determining how many of each type of user is being invited.
* Used for logging and sending analytics related to invites.
*
* @param {Array} inviteItems - An array with the invite items, as created
* in {@link _parseQueryResults}.
* @private
* @returns {Object} An object with keys as user types and values as the
* number of invites for that type.
*/
export function getInviteTypeCounts(inviteItems: Array<Object> = []) {
const inviteTypeCounts = {};
inviteItems.forEach(({ type }) => {
if (!inviteTypeCounts[type]) {
inviteTypeCounts[type] = 0;
}
inviteTypeCounts[type]++;
});
return inviteTypeCounts;
}

@ -6,6 +6,7 @@ import { NativeEventEmitter, NativeModules } from 'react-native';
import { MiddlewareRegistry } from '../base/redux';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
import { invite } from './actions';
import {
BEGIN_ADD_PEOPLE,
_SET_EMITTER_SUBSCRIPTIONS
@ -15,7 +16,6 @@ import {
isAddPeopleEnabled,
isDialOutEnabled
} from './functions';
import { sendInvitesForItems } from './actions';
import './middleware.any';
/**
@ -133,8 +133,7 @@ function _beginAddPeople({ getState }, next, action) {
* @param {Object} event - The details of the event.
* @returns {void}
*/
function _onInvite(
{ addPeopleControllerScope, externalAPIScope, invitees }) {
function _onInvite({ addPeopleControllerScope, externalAPIScope, invitees }) {
const { dispatch, getState } = this; // eslint-disable-line no-invalid-this
// If there are multiple JitsiMeetView instances alive, they will all get
@ -145,7 +144,7 @@ function _onInvite(
return;
}
dispatch(sendInvitesForItems(invitees))
dispatch(invite(invitees))
.then(failedInvitees =>
Invite.inviteSettled(
externalAPIScope,

Loading…
Cancel
Save