浏览代码

Merge pull request #9204 from jitsi/tavram/sip-fixes

fix(sip) allow sip invites to contain phone numbers
j8
Avram Tudor 4 年前
父节点
当前提交
7db9fc94e2
没有帐户链接到提交者的电子邮件

+ 5
- 8
lang/main.json 查看文件

5
         "copyInvite": "Copy meeting invitation",
5
         "copyInvite": "Copy meeting invitation",
6
         "copyLink": "Copy meeting link",
6
         "copyLink": "Copy meeting link",
7
         "copyStream": "Copy live streaming link",
7
         "copyStream": "Copy live streaming link",
8
+        "contacts": "contacts",
8
         "countryNotSupported": "We do not support this destination yet.",
9
         "countryNotSupported": "We do not support this destination yet.",
9
         "countryReminder": "Calling outside the US? Please make sure you start with the country code!",
10
         "countryReminder": "Calling outside the US? Please make sure you start with the country code!",
10
         "defaultEmail": "Your Default Email",
11
         "defaultEmail": "Your Default Email",
16
         "inviteMoreMailSubject": "Join {{appName}} meeting",
17
         "inviteMoreMailSubject": "Join {{appName}} meeting",
17
         "inviteMorePrompt": "Invite more people",
18
         "inviteMorePrompt": "Invite more people",
18
         "linkCopied": "Link copied to clipboard",
19
         "linkCopied": "Link copied to clipboard",
19
-        "loading": "Searching for people and phone numbers",
20
-        "loadingNumber": "Validating phone number",
21
-        "loadingPeople": "Searching for people to invite",
22
         "noResults": "No matching search results",
20
         "noResults": "No matching search results",
23
-        "noValidNumbers": "Please enter a phone number",
24
         "outlookEmail": "Outlook Email",
21
         "outlookEmail": "Outlook Email",
25
-        "searchNumbers": "Add phone numbers",
26
-        "searchPeople": "Search for people",
27
-        "searchPeopleAndNumbers": "Search for people or add their phone numbers",
22
+        "phoneNumbers": "phone numbers",
23
+        "searching": "Searching...",
28
         "shareInvite": "Share meeting invitation",
24
         "shareInvite": "Share meeting invitation",
29
         "shareLink": "Share the meeting link to invite others",
25
         "shareLink": "Share the meeting link to invite others",
30
         "shareStream": "Share the live streaming link",
26
         "shareStream": "Share the live streaming link",
31
-        "sip": "SIP: {{address}}",
27
+        "sipAddresses": "sip addresses",
32
         "telephone": "Telephone: {{number}}",
28
         "telephone": "Telephone: {{number}}",
33
         "title": "Invite people to this meeting",
29
         "title": "Invite people to this meeting",
34
         "yahooEmail": "Yahoo Email"
30
         "yahooEmail": "Yahoo Email"
379
         "inviteLiveStream": "To view the live stream of this meeting, click this link: {{url}}",
375
         "inviteLiveStream": "To view the live stream of this meeting, click this link: {{url}}",
380
         "invitePhone": "To join by phone instead, tap this: {{number}},,{{conferenceID}}#\n",
376
         "invitePhone": "To join by phone instead, tap this: {{number}},,{{conferenceID}}#\n",
381
         "invitePhoneAlternatives": "Looking for a different dial-in number?\nSee meeting dial-in numbers: {{url}}\n\n\nIf also dialing-in through a room phone, join without connecting to audio: {{silentUrl}}",
377
         "invitePhoneAlternatives": "Looking for a different dial-in number?\nSee meeting dial-in numbers: {{url}}\n\n\nIf also dialing-in through a room phone, join without connecting to audio: {{silentUrl}}",
378
+        "inviteSipEndpoint": "To join using the SIP address, enter this: {{sipUri}}",
382
         "inviteURLFirstPartGeneral": "You are invited to join a meeting.",
379
         "inviteURLFirstPartGeneral": "You are invited to join a meeting.",
383
         "inviteURLFirstPartPersonal": "{{name}} is inviting you to a meeting.\n",
380
         "inviteURLFirstPartPersonal": "{{name}} is inviting you to a meeting.\n",
384
         "inviteURLSecondPart": "\nJoin the meeting:\n{{url}}\n",
381
         "inviteURLSecondPart": "\nJoin the meeting:\n{{url}}\n",

+ 3
- 2
react/features/invite/actions.any.js 查看文件

215
             getDialInNumbers(dialInNumbersUrl, room, mucURL),
215
             getDialInNumbers(dialInNumbersUrl, room, mucURL),
216
             getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
216
             getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
217
         ])
217
         ])
218
-            .then(([ dialInNumbers, { conference, id, message } ]) => {
218
+            .then(([ dialInNumbers, { conference, id, message, sipUri } ]) => {
219
                 if (!conference || !id) {
219
                 if (!conference || !id) {
220
                     return Promise.reject(message);
220
                     return Promise.reject(message);
221
                 }
221
                 }
223
                 dispatch({
223
                 dispatch({
224
                     type: UPDATE_DIAL_IN_NUMBERS_SUCCESS,
224
                     type: UPDATE_DIAL_IN_NUMBERS_SUCCESS,
225
                     conferenceID: id,
225
                     conferenceID: id,
226
-                    dialInNumbers
226
+                    dialInNumbers,
227
+                    sipUri
227
                 });
228
                 });
228
             })
229
             })
229
             .catch(error => {
230
             .catch(error => {

+ 31
- 20
react/features/invite/components/add-people-dialog/web/InviteContactsForm.js 查看文件

57
 
57
 
58
     _resourceClient: Object;
58
     _resourceClient: Object;
59
 
59
 
60
+    _translations: Object;
61
+
60
     state = {
62
     state = {
61
         addToCallError: false,
63
         addToCallError: false,
62
         addToCallInProgress: false,
64
         addToCallInProgress: false,
86
             makeQuery: this._query,
88
             makeQuery: this._query,
87
             parseResults: this._parseQueryResults
89
             parseResults: this._parseQueryResults
88
         };
90
         };
91
+
92
+
93
+        const { t } = props;
94
+
95
+        this._translations = {
96
+            _dialOutEnabled: t('addPeople.phoneNumbers'),
97
+            _addPeopleEnabled: t('addPeople.contacts'),
98
+            _sipInviteEnabled: t('addPeople.sipAddresses')
99
+        };
100
+
89
     }
101
     }
90
 
102
 
91
     /**
103
     /**
118
             _addPeopleEnabled,
130
             _addPeopleEnabled,
119
             _dialOutEnabled,
131
             _dialOutEnabled,
120
             _isVpaas,
132
             _isVpaas,
133
+            _sipInviteEnabled,
121
             t
134
             t
122
         } = this.props;
135
         } = this.props;
123
         const footerText = this._renderFooterText();
136
         const footerText = this._renderFooterText();
124
         let isMultiSelectDisabled = this.state.addToCallInProgress;
137
         let isMultiSelectDisabled = this.state.addToCallInProgress;
125
-        let placeholder;
126
-        let loadingMessage;
127
-        let noMatches;
128
-
129
-        if (_addPeopleEnabled && _dialOutEnabled) {
130
-            loadingMessage = 'addPeople.loading';
131
-            noMatches = 'addPeople.noResults';
132
-            placeholder = 'addPeople.searchPeopleAndNumbers';
133
-        } else if (_addPeopleEnabled) {
134
-            loadingMessage = 'addPeople.loadingPeople';
135
-            noMatches = 'addPeople.noResults';
136
-            placeholder = 'addPeople.searchPeople';
137
-        } else if (_dialOutEnabled) {
138
-            loadingMessage = 'addPeople.loadingNumber';
139
-            noMatches = 'addPeople.noValidNumbers';
140
-            placeholder = 'addPeople.searchNumbers';
141
-        } else {
138
+        const loadingMessage = 'addPeople.searching';
139
+        const noMatches = 'addPeople.noResults';
140
+
141
+        const features = {
142
+            _dialOutEnabled,
143
+            _addPeopleEnabled,
144
+            _sipInviteEnabled
145
+        };
146
+
147
+        const computedPlaceholder = Object.keys(features)
148
+            .filter(v => Boolean(features[v]))
149
+            .map(v => this._translations[v])
150
+            .join(', ');
151
+
152
+        const placeholder = computedPlaceholder ? `${t('dialog.add')} ${computedPlaceholder}` : t('addPeople.disabled');
153
+
154
+        if (!computedPlaceholder) {
142
             isMultiSelectDisabled = true;
155
             isMultiSelectDisabled = true;
143
-            noMatches = 'addPeople.noResults';
144
-            placeholder = 'addPeople.disabled';
145
         }
156
         }
146
 
157
 
147
         return (
158
         return (
156
                     noMatchesFound = { t(noMatches) }
167
                     noMatchesFound = { t(noMatches) }
157
                     onItemSelected = { this._onItemSelected }
168
                     onItemSelected = { this._onItemSelected }
158
                     onSelectionChange = { this._onSelectionChange }
169
                     onSelectionChange = { this._onSelectionChange }
159
-                    placeholder = { t(placeholder) }
170
+                    placeholder = { placeholder }
160
                     ref = { this._setMultiSelectElement }
171
                     ref = { this._setMultiSelectElement }
161
                     resourceClient = { this._resourceClient }
172
                     resourceClient = { this._resourceClient }
162
                     shouldFitContainer = { true }
173
                     shouldFitContainer = { true }

+ 1
- 1
react/features/invite/constants.js 查看文件

47
  * Regex for matching sip addresses.
47
  * Regex for matching sip addresses.
48
  */
48
  */
49
 // eslint-disable-next-line max-len
49
 // eslint-disable-next-line max-len
50
-export const SIP_ADDRESS_REGEX = /^[a-zA-Z]+(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/;
50
+export const SIP_ADDRESS_REGEX = /^[+a-zA-Z0-9]+(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/;
51
 
51
 
52
 /**
52
 /**
53
  * Different invite types mapping
53
  * Different invite types mapping

+ 8
- 0
react/features/invite/functions.js 查看文件

301
         invite = `${invite}\n${dial}\n${moreNumbers}`;
301
         invite = `${invite}\n${dial}\n${moreNumbers}`;
302
     }
302
     }
303
 
303
 
304
+    if (dialIn.sipUri) {
305
+        const sipText = t('info.inviteSipEndpoint', {
306
+            sipUri: dialIn.sipUri
307
+        });
308
+
309
+        invite = `${invite}\n${sipText}`;
310
+    }
311
+
304
     return invite;
312
     return invite;
305
 }
313
 }
306
 
314
 

+ 1
- 0
react/features/invite/reducer.js 查看文件

60
                 ...state,
60
                 ...state,
61
                 conferenceID: action.conferenceID,
61
                 conferenceID: action.conferenceID,
62
                 numbers: action.dialInNumbers,
62
                 numbers: action.dialInNumbers,
63
+                sipUri: action.sipUri,
63
                 numbersEnabled: true,
64
                 numbersEnabled: true,
64
                 numbersFetched: true
65
                 numbersFetched: true
65
             };
66
             };

+ 8
- 1
react/features/lobby/components/AbstractLobbyScreen.js 查看文件

46
      */
46
      */
47
     _passwordJoinFailed: boolean,
47
     _passwordJoinFailed: boolean,
48
 
48
 
49
+    /**
50
+     * True if the password field should be available for lobby participants.
51
+     */
52
+     _renderPassword: boolean,
53
+
49
     /**
54
     /**
50
      * The Redux dispatch function.
55
      * The Redux dispatch function.
51
      */
56
      */
365
     const localParticipant = getLocalParticipant(state);
370
     const localParticipant = getLocalParticipant(state);
366
     const participantId = localParticipant?.id;
371
     const participantId = localParticipant?.id;
367
     const { knocking, passwordJoinFailed } = state['features/lobby'];
372
     const { knocking, passwordJoinFailed } = state['features/lobby'];
373
+    const { iAmSipGateway } = state['features/base/config'];
368
 
374
 
369
     return {
375
     return {
370
         _knocking: knocking,
376
         _knocking: knocking,
372
         _participantEmail: localParticipant?.email,
378
         _participantEmail: localParticipant?.email,
373
         _participantId: participantId,
379
         _participantId: participantId,
374
         _participantName: localParticipant?.name,
380
         _participantName: localParticipant?.name,
375
-        _passwordJoinFailed: passwordJoinFailed
381
+        _passwordJoinFailed: passwordJoinFailed,
382
+        _renderPassword: !iAmSipGateway
376
     };
383
     };
377
 }
384
 }

+ 3
- 3
react/features/lobby/components/native/LobbyScreen.js 查看文件

208
      * @inheritdoc
208
      * @inheritdoc
209
      */
209
      */
210
     _renderStandardButtons() {
210
     _renderStandardButtons() {
211
-        const { _knocking, t } = this.props;
211
+        const { _knocking, _renderPassword, t } = this.props;
212
 
212
 
213
         return (
213
         return (
214
             <>
214
             <>
223
                         { t('lobby.knockButton') }
223
                         { t('lobby.knockButton') }
224
                     </Text>
224
                     </Text>
225
                 </TouchableOpacity> }
225
                 </TouchableOpacity> }
226
-                <TouchableOpacity
226
+                { _renderPassword && <TouchableOpacity
227
                     onPress = { this._onSwitchToPasswordMode }
227
                     onPress = { this._onSwitchToPasswordMode }
228
                     style = { [
228
                     style = { [
229
                         styles.button,
229
                         styles.button,
232
                     <Text>
232
                     <Text>
233
                         { t('lobby.enterPasswordButton') }
233
                         { t('lobby.enterPasswordButton') }
234
                     </Text>
234
                     </Text>
235
-                </TouchableOpacity>
235
+                </TouchableOpacity> }
236
             </>
236
             </>
237
         );
237
         );
238
     }
238
     }

+ 3
- 3
react/features/lobby/components/web/LobbyScreen.js 查看文件

152
      * @inheritdoc
152
      * @inheritdoc
153
      */
153
      */
154
     _renderStandardButtons() {
154
     _renderStandardButtons() {
155
-        const { _knocking, t } = this.props;
155
+        const { _knocking, _renderPassword, t } = this.props;
156
 
156
 
157
         return (
157
         return (
158
             <>
158
             <>
163
                     type = 'primary'>
163
                     type = 'primary'>
164
                     { t('lobby.knockButton') }
164
                     { t('lobby.knockButton') }
165
                 </ActionButton> }
165
                 </ActionButton> }
166
-                <ActionButton
166
+                {_renderPassword && <ActionButton
167
                     onClick = { this._onSwitchToPasswordMode }
167
                     onClick = { this._onSwitchToPasswordMode }
168
                     testId = 'lobby.enterPasswordButton'
168
                     testId = 'lobby.enterPasswordButton'
169
                     type = 'secondary'>
169
                     type = 'secondary'>
170
                     { t('lobby.enterPasswordButton') }
170
                     { t('lobby.enterPasswordButton') }
171
-                </ActionButton>
171
+                </ActionButton> }
172
             </>
172
             </>
173
         );
173
         );
174
     }
174
     }

正在加载...
取消
保存