Преглед на файлове

Adds dial in default number and pin to the text for calendar/share. (#3421)

* Adds dial in default number and pin to the text for calendar/share.

* Handles fail to fetch numbers or conference id.
master
Дамян Минков преди 7 години
родител
ревизия
7674e90d4d
No account linked to committer's email address

+ 1
- 1
lang/main.json Целия файл

430
     "share":
430
     "share":
431
     {
431
     {
432
         "mainText": "Click the following link to join the meeting:\n__roomUrl__",
432
         "mainText": "Click the following link to join the meeting:\n__roomUrl__",
433
-        "dialInfoText": "\n\n=====\n\nJust want to dial in on your phone?\n\nClick this link to see the dial in phone numbers for this meetings\n__dialInfoPageUrl__"
433
+        "dialInfoText": "\n\n=====\n\nJust want to dial in on your phone?\n\n__defaultDialInNumber__Click this link to see the dial in phone numbers for this meeting\n__dialInfoPageUrl__"
434
     },
434
     },
435
     "connection":
435
     "connection":
436
     {
436
     {

+ 26
- 27
react/features/calendar-sync/web/microsoftCalendar.js Целия файл

329
                 return Promise.reject('Not authorized, please sign in!');
329
                 return Promise.reject('Not authorized, please sign in!');
330
             }
330
             }
331
 
331
 
332
-            const { dialInNumbersUrl } = getState()['features/base/config'];
333
-            const text = getShareInfoText(
334
-                location, dialInNumbersUrl !== undefined, true/* use html */);
335
-
336
-
337
-            const client = Client.init({
338
-                authProvider: done => done(null, token)
339
-            });
340
-
341
-            return client
342
-                .api(`/me/events/${id}`)
343
-                .get()
344
-                .then(description => {
345
-                    const body = description.body;
346
-
347
-                    if (description.bodyPreview) {
348
-                        body.content = `${description.bodyPreview}<br><br>`;
349
-                    }
350
-
351
-                    // replace all new lines from the text with html <br>
352
-                    // to make it pretty
353
-                    body.content += text.split('\n').join('<br>');
332
+            return getShareInfoText(getState(), location, true/* use html */)
333
+                .then(text => {
334
+                    const client = Client.init({
335
+                        authProvider: done => done(null, token)
336
+                    });
354
 
337
 
355
                     return client
338
                     return client
356
-                        .api(`/me/calendar/events/${id}`)
357
-                        .patch({
358
-                            body,
359
-                            location: {
360
-                                'displayName': location
339
+                        .api(`/me/events/${id}`)
340
+                        .get()
341
+                        .then(description => {
342
+                            const body = description.body;
343
+
344
+                            if (description.bodyPreview) {
345
+                                body.content
346
+                                    = `${description.bodyPreview}<br><br>`;
361
                             }
347
                             }
348
+
349
+                            // replace all new lines from the text with html
350
+                            // <br> to make it pretty
351
+                            body.content += text.split('\n').join('<br>');
352
+
353
+                            return client
354
+                                .api(`/me/calendar/events/${id}`)
355
+                                .patch({
356
+                                    body,
357
+                                    location: {
358
+                                        'displayName': location
359
+                                    }
360
+                                });
362
                         });
361
                         });
363
                 });
362
                 });
364
         };
363
         };

+ 3
- 8
react/features/google-api/actions.js Целия файл

211
  */
211
  */
212
 export function updateCalendarEvent(
212
 export function updateCalendarEvent(
213
         id: string, calendarId: string, location: string) {
213
         id: string, calendarId: string, location: string) {
214
-    return (dispatch: Dispatch<*>, getState: Function) => {
215
-
216
-        const { dialInNumbersUrl } = getState()['features/base/config'];
217
-        const text = getShareInfoText(location, dialInNumbersUrl !== undefined);
218
-
219
-        return googleApi.get()
220
-            .then(() =>
214
+    return (dispatch: Dispatch<*>, getState: Function) =>
215
+        getShareInfoText(getState(), location)
216
+            .then(text =>
221
                 googleApi._updateCalendarEntry(id, calendarId, location, text));
217
                 googleApi._updateCalendarEntry(id, calendarId, location, text));
222
-    };
223
 }
218
 }

+ 2
- 3
react/features/invite/components/dial-in-info-page/DialInInfoApp.web.js Целия файл

10
 import NoRoomError from './NoRoomError';
10
 import NoRoomError from './NoRoomError';
11
 
11
 
12
 document.addEventListener('DOMContentLoaded', () => {
12
 document.addEventListener('DOMContentLoaded', () => {
13
-    const params = parseURLParams(window.location, true, 'search');
14
-    const { room } = params;
13
+    const { room } = parseURLParams(window.location, true, 'search');
15
 
14
 
16
     ReactDOM.render(
15
     ReactDOM.render(
17
         <I18nextProvider i18n = { i18next }>
16
         <I18nextProvider i18n = { i18next }>
19
                 ? <DialInSummary
18
                 ? <DialInSummary
20
                     className = 'dial-in-page'
19
                     className = 'dial-in-page'
21
                     clickableNumbers = { false }
20
                     clickableNumbers = { false }
22
-                    room = { params.room } />
21
+                    room = { room } />
23
                 : <NoRoomError className = 'dial-in-page' /> }
22
                 : <NoRoomError className = 'dial-in-page' /> }
24
         </I18nextProvider>,
23
         </I18nextProvider>,
25
         document.getElementById('react')
24
         document.getElementById('react')

+ 12
- 34
react/features/invite/components/info-dialog/InfoDialog.web.js Целия файл

7
 import { translate } from '../../../base/i18n';
7
 import { translate } from '../../../base/i18n';
8
 import { isLocalParticipantModerator } from '../../../base/participants';
8
 import { isLocalParticipantModerator } from '../../../base/participants';
9
 
9
 
10
-import { getDialInfoPageURL } from '../../functions';
10
+import { _getDefaultPhoneNumber, getDialInfoPageURL } from '../../functions';
11
 import DialInNumber from './DialInNumber';
11
 import DialInNumber from './DialInNumber';
12
 import PasswordForm from './PasswordForm';
12
 import PasswordForm from './PasswordForm';
13
 
13
 
49
          */
49
          */
50
         _inviteURL: PropTypes.string,
50
         _inviteURL: PropTypes.string,
51
 
51
 
52
+        /**
53
+         * The current location url of the conference.
54
+         */
55
+        _locationURL: PropTypes.object,
56
+
52
         /**
57
         /**
53
          * The value for how the conference is locked (or undefined if not
58
          * The value for how the conference is locked (or undefined if not
54
          * locked) as defined by room-lock constants.
59
          * locked) as defined by room-lock constants.
118
 
123
 
119
         if (numbers) {
124
         if (numbers) {
120
             this.state.phoneNumber
125
             this.state.phoneNumber
121
-                = this._getDefaultPhoneNumber(numbers, defaultCountry);
126
+                = _getDefaultPhoneNumber(numbers, defaultCountry);
122
         }
127
         }
123
 
128
 
124
         /**
129
         /**
157
             const { defaultCountry, numbers } = nextProps.dialIn;
162
             const { defaultCountry, numbers } = nextProps.dialIn;
158
 
163
 
159
             this.setState({
164
             this.setState({
160
-                phoneNumber:
161
-                    this._getDefaultPhoneNumber(numbers, defaultCountry)
165
+                phoneNumber: _getDefaultPhoneNumber(numbers, defaultCountry)
162
             });
166
             });
163
         }
167
         }
164
     }
168
     }
231
         );
235
         );
232
     }
236
     }
233
 
237
 
234
-    /**
235
-     * Sets the internal state of which dial-in number to display.
236
-     *
237
-     * @param {Array<string>|Object} dialInNumbers - The array or object of
238
-     * numbers to choose a number from.
239
-     * @param {string} defaultCountry - The country code for the country
240
-     * whose phone number should display.
241
-     * @private
242
-     * @returns {string|null}
243
-     */
244
-    _getDefaultPhoneNumber(dialInNumbers, defaultCountry = 'US') {
245
-        if (Array.isArray(dialInNumbers)) {
246
-            // Dumbly return the first number if an array.
247
-            return dialInNumbers[0];
248
-        } else if (Object.keys(dialInNumbers).length > 0) {
249
-            const defaultNumbers = dialInNumbers[defaultCountry];
250
-
251
-            if (defaultNumbers) {
252
-                return defaultNumbers[0];
253
-            }
254
-
255
-            const firstRegion = Object.keys(dialInNumbers)[0];
256
-
257
-            return firstRegion && firstRegion[0];
258
-        }
259
-
260
-        return null;
261
-    }
262
-
263
     /**
238
     /**
264
      * Generates the URL for the static dial in info page.
239
      * Generates the URL for the static dial in info page.
265
      *
240
      *
268
      */
243
      */
269
     _getDialInfoPageURL() {
244
     _getDialInfoPageURL() {
270
         return getDialInfoPageURL(
245
         return getDialInfoPageURL(
271
-            encodeURIComponent(this.props._conferenceName));
246
+            encodeURIComponent(this.props._conferenceName),
247
+            this.props._locationURL);
272
     }
248
     }
273
 
249
 
274
     /**
250
     /**
525
  *     _conference: Object,
501
  *     _conference: Object,
526
  *     _conferenceName: string,
502
  *     _conferenceName: string,
527
  *     _inviteURL: string,
503
  *     _inviteURL: string,
504
+ *     _locationURL: string,
528
  *     _locked: string,
505
  *     _locked: string,
529
  *     _password: string
506
  *     _password: string
530
  * }}
507
  * }}
542
         _conference: conference,
519
         _conference: conference,
543
         _conferenceName: room,
520
         _conferenceName: room,
544
         _inviteURL: getInviteURL(state),
521
         _inviteURL: getInviteURL(state),
522
+        _locationURL: state['features/base/connection'].locationURL,
545
         _locked: locked,
523
         _locked: locked,
546
         _password: password
524
         _password: password
547
     };
525
     };

+ 107
- 14
react/features/invite/functions.js Целия файл

403
  * Returns descriptive text that can be used to invite participants to a meeting
403
  * Returns descriptive text that can be used to invite participants to a meeting
404
  * (share via mobile or use it for calendar event description).
404
  * (share via mobile or use it for calendar event description).
405
  *
405
  *
406
+ * @param {Object} state - The current state.
406
  * @param {string} inviteUrl - The conference/location URL.
407
  * @param {string} inviteUrl - The conference/location URL.
407
- * @param {boolean} includeDialInfo - Whether to include or not the dialing
408
- * information link.
409
  * @param {boolean} useHtml - Whether to return html text.
408
  * @param {boolean} useHtml - Whether to return html text.
410
- * @returns {string}
409
+ * @returns {Promise<string>} A {@code Promise} resolving with a
410
+ * descriptive text that can be used to invite participants to a meeting.
411
  */
411
  */
412
 export function getShareInfoText(
412
 export function getShareInfoText(
413
-        inviteUrl: string, includeDialInfo: boolean, useHtml: ?boolean) {
413
+        state: Object, inviteUrl: string, useHtml: ?boolean): Promise<string> {
414
     let roomUrl = inviteUrl;
414
     let roomUrl = inviteUrl;
415
+    const includeDialInfo = state['features/base/config'] !== undefined;
415
 
416
 
416
     if (useHtml) {
417
     if (useHtml) {
417
         roomUrl = `<a href="${roomUrl}">${roomUrl}</a>`;
418
         roomUrl = `<a href="${roomUrl}">${roomUrl}</a>`;
421
 
422
 
422
     if (includeDialInfo) {
423
     if (includeDialInfo) {
423
         const { room } = parseURIString(inviteUrl);
424
         const { room } = parseURIString(inviteUrl);
424
-        let dialInfoPageUrl = getDialInfoPageURL(room);
425
+        let numbersPromise;
426
+
427
+        if (state['features/invite'].numbers
428
+            && state['features/invite'].conferenceID) {
429
+            numbersPromise = Promise.resolve(state['features/invite']);
430
+        } else {
431
+            // we are requesting numbers and conferenceId directly
432
+            // not using updateDialInNumbers, because custom room
433
+            // is specified and we do not want to store the data
434
+            // in the state
435
+            const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
436
+                = state['features/base/config'];
437
+            const mucURL = hosts && hosts.muc;
438
+
439
+            if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
440
+                // URLs for fetching dial in numbers not defined
441
+                return Promise.reject();
442
+            }
443
+
444
+            numbersPromise = Promise.all([
445
+                getDialInNumbers(dialInNumbersUrl),
446
+                getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
447
+            ]).then(([ { defaultCountry, numbers }, {
448
+                conference, id, message } ]) => {
425
 
449
 
426
-        if (useHtml) {
427
-            dialInfoPageUrl
428
-                = `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
450
+                if (!conference || !id) {
451
+                    return Promise.reject(message);
452
+                }
453
+
454
+                return {
455
+                    defaultCountry,
456
+                    numbers,
457
+                    conferenceID: id
458
+                };
459
+            });
429
         }
460
         }
430
 
461
 
431
-        infoText += i18next.t('share.dialInfoText', { dialInfoPageUrl });
462
+        return numbersPromise.then(
463
+            ({ conferenceID, defaultCountry, numbers }) => {
464
+                const phoneNumber
465
+                    = _getDefaultPhoneNumber(numbers, defaultCountry) || '';
466
+
467
+                return `${
468
+                    i18next.t('info.dialInNumber')} ${
469
+                    phoneNumber} ${
470
+                    i18next.t('info.dialInConferenceID')} ${
471
+                    conferenceID}#\n\n`;
472
+            })
473
+            .catch(error =>
474
+                logger.error('Error fetching numbers or conferenceID', error))
475
+            .then(defaultDialInNumber => {
476
+                let dialInfoPageUrl = getDialInfoPageURL(
477
+                    room,
478
+                    state['features/base/connection'].locationURL);
479
+
480
+                if (useHtml) {
481
+                    dialInfoPageUrl
482
+                        = `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
483
+                }
484
+
485
+                infoText += i18next.t('share.dialInfoText', {
486
+                    defaultDialInNumber,
487
+                    dialInfoPageUrl });
488
+
489
+                return infoText;
490
+            });
432
     }
491
     }
433
 
492
 
434
-    return infoText;
493
+    return Promise.resolve(infoText);
435
 }
494
 }
436
 
495
 
437
 /**
496
 /**
438
  * Generates the URL for the static dial in info page.
497
  * Generates the URL for the static dial in info page.
439
  *
498
  *
440
  * @param {string} conferenceName - The conference name.
499
  * @param {string} conferenceName - The conference name.
441
- * @private
500
+ * @param {Object} locationURL - The current location URL, the object coming
501
+ * from state ['features/base/connection'].locationURL.
442
  * @returns {string}
502
  * @returns {string}
443
  */
503
  */
444
-export function getDialInfoPageURL(conferenceName: string) {
445
-    const origin = window.location.origin;
446
-    const pathParts = window.location.pathname.split('/');
504
+export function getDialInfoPageURL(
505
+        conferenceName: string,
506
+        locationURL: Object) {
507
+    const origin = locationURL.origin;
508
+    const pathParts = locationURL.pathname.split('/');
447
 
509
 
448
     pathParts.length = pathParts.length - 1;
510
     pathParts.length = pathParts.length - 1;
449
 
511
 
457
 
519
 
458
     return `${origin}${newPath}/static/dialInInfo.html?room=${conferenceName}`;
520
     return `${origin}${newPath}/static/dialInInfo.html?room=${conferenceName}`;
459
 }
521
 }
522
+
523
+/**
524
+ * Sets the internal state of which dial-in number to display.
525
+ *
526
+ * @param {Array<string>|Object} dialInNumbers - The array or object of
527
+ * numbers to choose a number from.
528
+ * @param {string} defaultCountry - The country code for the country
529
+ * whose phone number should display.
530
+ * @private
531
+ * @returns {string|null}
532
+ */
533
+export function _getDefaultPhoneNumber(
534
+        dialInNumbers: Object,
535
+        defaultCountry: string = 'US') {
536
+    if (Array.isArray(dialInNumbers)) {
537
+        // Dumbly return the first number if an array.
538
+        return dialInNumbers[0];
539
+    } else if (Object.keys(dialInNumbers).length > 0) {
540
+        const defaultNumbers = dialInNumbers[defaultCountry];
541
+
542
+        if (defaultNumbers) {
543
+            return defaultNumbers[0];
544
+        }
545
+
546
+        const firstRegion = Object.keys(dialInNumbers)[0];
547
+
548
+        return firstRegion && firstRegion[0];
549
+    }
550
+
551
+    return null;
552
+}

+ 1
- 3
react/features/share-room/actions.js Целия файл

19
         }
19
         }
20
         roomURL && dispatch({
20
         roomURL && dispatch({
21
             type: BEGIN_SHARE_ROOM,
21
             type: BEGIN_SHARE_ROOM,
22
-            roomURL,
23
-            includeDialInfo: getState()['features/base/config']
24
-                .dialInNumbersUrl !== undefined
22
+            roomURL
25
         });
23
         });
26
     };
24
     };
27
 }
25
 }

+ 28
- 29
react/features/share-room/middleware.js Целия файл

21
 MiddlewareRegistry.register(store => next => action => {
21
 MiddlewareRegistry.register(store => next => action => {
22
     switch (action.type) {
22
     switch (action.type) {
23
     case BEGIN_SHARE_ROOM:
23
     case BEGIN_SHARE_ROOM:
24
-        _shareRoom(action.roomURL, action.includeDialInfo, store.dispatch);
24
+        _shareRoom(action.roomURL, store);
25
         break;
25
         break;
26
     }
26
     }
27
 
27
 
32
  * Open the native sheet for sharing a specific conference/room URL.
32
  * Open the native sheet for sharing a specific conference/room URL.
33
  *
33
  *
34
  * @param {string} roomURL - The URL of the conference/room to be shared.
34
  * @param {string} roomURL - The URL of the conference/room to be shared.
35
- * @param {boolean} includeDialInfo - Whether to include or not the dialing
36
- * information link.
37
- * @param {Dispatch} dispatch - The Redux dispatch function.
35
+ * @param {Store} store - Redux store.
38
  * @private
36
  * @private
39
  * @returns {void}
37
  * @returns {void}
40
  */
38
  */
41
-function _shareRoom(
42
-        roomURL: string, includeDialInfo: boolean, dispatch: Function) {
43
-    const message = getShareInfoText(roomURL, includeDialInfo);
44
-    const title = `${getName()} Conference`;
45
-    const onFulfilled
46
-        = (shared: boolean) => dispatch(endShareRoom(roomURL, shared));
39
+function _shareRoom(roomURL: string, { dispatch, getState }) {
40
+    getShareInfoText(getState(), roomURL)
41
+        .then(message => {
42
+            const title = `${getName()} Conference`;
43
+            const onFulfilled
44
+                = (shared: boolean) => dispatch(endShareRoom(roomURL, shared));
47
 
45
 
48
-    Share.share(
49
-        /* content */ {
50
-            message,
51
-            title
52
-        },
53
-        /* options */ {
54
-            dialogTitle: title, // Android
55
-            subject: title // iOS
56
-        })
57
-        .then(
58
-            /* onFulfilled */ value => {
59
-                onFulfilled(value.action === Share.sharedAction);
60
-            },
61
-            /* onRejected */ reason => {
62
-                logger.error(
63
-                    `Failed to share conference/room URL ${roomURL}:`,
64
-                    reason);
65
-                onFulfilled(false);
66
-            });
46
+            Share.share(
47
+                /* content */ {
48
+                    message,
49
+                    title
50
+                },
51
+                /* options */ {
52
+                    dialogTitle: title, // Android
53
+                    subject: title // iOS
54
+                })
55
+                .then(
56
+                    /* onFulfilled */ value => {
57
+                        onFulfilled(value.action === Share.sharedAction);
58
+                    },
59
+                    /* onRejected */ reason => {
60
+                        logger.error(
61
+                            `Failed to share conference/room URL ${roomURL}:`,
62
+                            reason);
63
+                        onFulfilled(false);
64
+                    });
65
+        });
67
 }
66
 }

Loading…
Отказ
Запис