Quellcode durchsuchen

[RN] Support XMPP authentication

j8
Lyubo Marinov vor 8 Jahren
Ursprung
Commit
241dc3b147

+ 1
- 1
lang/main.json Datei anzeigen

@@ -264,7 +264,7 @@
264 264
         "removeSharedVideoMsg": "Are you sure you would like to remove your shared video?",
265 265
         "alreadySharedVideoMsg": "Another member is already sharing video. This conference allows only one shared video at a time.",
266 266
         "WaitingForHost": "Waiting for the host ...",
267
-        "WaitForHostMsg": "The conference '__room__' has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
267
+        "WaitForHostMsg": "The conference <b>__room__ </b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
268 268
         "IamHost": "I am the host",
269 269
         "Cancel": "Cancel",
270 270
         "Submit": "Submit",

+ 28
- 25
modules/UI/authentication/AuthHandler.js Datei anzeigen

@@ -139,38 +139,41 @@ function initJWTTokenListener(room) {
139 139
  * @param {JitsiConference} room
140 140
  * @param {string} [lockPassword] password to use if the conference is locked
141 141
  */
142
-function doXmppAuth (room, lockPassword) {
143
-    const loginDialog = LoginDialog.showAuthDialog(function (id, password) {
144
-        const authConnection = room.createAuthenticationConnection();
145
-
146
-        authConnection.authenticateAndUpgradeRole({
142
+function doXmppAuth(room, lockPassword) {
143
+    const loginDialog = LoginDialog.showAuthDialog(
144
+        /* successCallback */ (id, password) => {
145
+            room.authenticateAndUpgradeRole({
147 146
                 id,
148 147
                 password,
149 148
                 roomPassword: lockPassword,
150
-                onLoginSuccessful: () => { /* Called when XMPP login succeeds */
149
+
150
+                /** Called when the XMPP login succeeds. */
151
+                onLoginSuccessful() {
151 152
                     loginDialog.displayConnectionStatus(
152 153
                         'connection.FETCH_SESSION_ID');
153 154
                 }
154 155
             })
155
-            .then(() => {
156
-                loginDialog.displayConnectionStatus(
157
-                    'connection.GOT_SESSION_ID');
158
-                loginDialog.close();
159
-            })
160
-            .catch(error => {
161
-                logger.error('authenticateAndUpgradeRole failed', error);
162
-                if (error.authenticationError) {
163
-                    loginDialog.displayError(
164
-                        'connection.GET_SESSION_ID_ERROR', {
165
-                            msg: error.authenticationError
166
-                        });
167
-                } else {
168
-                    loginDialog.displayError(error.connectionError);
169
-                }
170
-            });
171
-    }, function () {
172
-        loginDialog.close();
173
-    });
156
+            .then(
157
+                /* onFulfilled */ () => {
158
+                    loginDialog.displayConnectionStatus(
159
+                        'connection.GOT_SESSION_ID');
160
+                    loginDialog.close();
161
+                },
162
+                /* onRejected */ error => {
163
+                    logger.error('authenticateAndUpgradeRole failed', error);
164
+
165
+                    const { authenticationError, connectionError } = error;
166
+
167
+                    if (authenticationError) {
168
+                        loginDialog.displayError(
169
+                            'connection.GET_SESSION_ID_ERROR',
170
+                            { msg: authenticationError });
171
+                    } else if (connectionError) {
172
+                        loginDialog.displayError(connectionError);
173
+                    }
174
+                });
175
+        },
176
+        /* cancelCallback */ () => loginDialog.close());
174 177
 }
175 178
 
176 179
 /**

+ 22
- 17
modules/UI/authentication/LoginDialog.js Datei anzeigen

@@ -1,4 +1,5 @@
1 1
 /* global $, APP, config, JitsiMeetJS */
2
+
2 3
 import { toJid } from '../../../react/features/base/connection';
3 4
 
4 5
 const ConnectionErrors = JitsiMeetJS.errors.connection;
@@ -196,34 +197,38 @@ export default {
196 197
     },
197 198
 
198 199
     /**
199
-     * Show notification that authentication is required
200
-     * to create the conference, so he should authenticate or wait for a host.
201
-     * @param {string} roomName name of the conference
202
-     * @param {function} onAuthNow callback to invoke if
203
-     * user want to authenticate.
200
+     * Shows a notification that authentication is required to create the
201
+     * conference, so the local participant should authenticate or wait for a
202
+     * host.
203
+     *
204
+     * @param {string} room - The name of the conference.
205
+     * @param {function} onAuthNow - The callback to invoke if the local
206
+     * participant wants to authenticate.
204 207
      * @returns dialog
205 208
      */
206
-    showAuthRequiredDialog: function (roomName, onAuthNow) {
207
-        var msg = APP.translation.generateTranslationHTML(
208
-            "dialog.WaitForHostMsg", {room: roomName}
209
+    showAuthRequiredDialog(room, onAuthNow) {
210
+        const msg = APP.translation.generateTranslationHTML(
211
+            '[html]dialog.WaitForHostMsg',
212
+            { room }
209 213
         );
210
-
211
-        var buttonTxt = APP.translation.generateTranslationHTML(
212
-            "dialog.IamHost"
214
+        const buttonTxt = APP.translation.generateTranslationHTML(
215
+            'dialog.IamHost'
213 216
         );
214
-        var buttons = [{title: buttonTxt, value: "authNow"}];
217
+        const buttons = [{
218
+            title: buttonTxt,
219
+            value: 'authNow'
220
+        }];
215 221
 
216 222
         return APP.UI.messageHandler.openDialog(
217
-            "dialog.WaitingForHost",
223
+            'dialog.WaitingForHost',
218 224
             msg,
219 225
             true,
220 226
             buttons,
221
-            function (e, submitValue) {
222
-
223
-                // Do not close the dialog yet
227
+            (e, submitValue) => {
228
+                // Do not close the dialog yet.
224 229
                 e.preventDefault();
225 230
 
226
-                // Open login popup
231
+                // Open login popup.
227 232
                 if (submitValue === 'authNow') {
228 233
                     onAuthNow();
229 234
                 }

+ 1
- 1
react/features/app/components/App.native.js Datei anzeigen

@@ -4,6 +4,7 @@ import React from 'react';
4 4
 import { Linking } from 'react-native';
5 5
 
6 6
 import '../../analytics';
7
+import '../../authentication';
7 8
 import { Platform } from '../../base/react';
8 9
 import '../../mobile/audio-mode';
9 10
 import '../../mobile/background';
@@ -15,7 +16,6 @@ import '../../mobile/proximity';
15 16
 import '../../mobile/wake-lock';
16 17
 
17 18
 import { AbstractApp } from './AbstractApp';
18
-import '../../authentication';
19 19
 
20 20
 /**
21 21
  * Root application component.

+ 16
- 23
react/features/authentication/actionTypes.js Datei anzeigen

@@ -28,38 +28,31 @@ export const CANCEL_WAIT_FOR_OWNER = Symbol('CANCEL_WAIT_FOR_OWNER');
28 28
  */
29 29
 export const STOP_WAIT_FOR_OWNER = Symbol('STOP_WAIT_FOR_OWNER');
30 30
 
31
-/**
32
- * The type of (redux) action which signals that the process of authenticating
33
- * and upgrading the current conference user's role has been started.
34
- *
35
- * {
36
- *     type: UPGRADE_ROLE_STARTED,
37
- *     authConnection: JitsiAuthConnection
38
- * }
39
- */
40
-export const UPGRADE_ROLE_STARTED = Symbol('UPGRADE_ROLE_STARTED');
41
-
42 31
 /**
43 32
  * The type of (redux) action which informs that the authentication and role
44
- * upgrade process has been completed successfully.
33
+ * upgrade process has finished either with success or with a specific error.
34
+ * If <tt>error</tt> is <tt>undefined</tt>, then the process succeeded;
35
+ * otherwise, it failed. Refer to
36
+ * {@link JitsiConference#authenticateAndUpgradeRole} in lib-jitsi-meet for the
37
+ * error details.
45 38
  *
46 39
  * {
47
- *      type: UPGRADE_ROLE_SUCCESS
40
+ *     type: UPGRADE_ROLE_FINISHED,
41
+ *     error: Object
48 42
  * }
49 43
  */
50
-export const UPGRADE_ROLE_SUCCESS = Symbol('UPGRADE_ROLE_SUCCESS');
44
+export const UPGRADE_ROLE_FINISHED = Symbol('UPGRADE_ROLE_FINISHED');
51 45
 
52 46
 /**
53
- * The type of (redux) action which informs that the authentication and role
54
- * upgrade process has failed with an error. Check the docs of
55
- * {@link JitsiAuthConnection} for more details about the error structure.
47
+ * The type of (redux) action which signals that the process of authenticating
48
+ * and upgrading the local participant's role has been started.
56 49
  *
57 50
  * {
58
- *      type: UPGRADE_ROLE_SUCCESS,
59
- *      error: Object
51
+ *     type: UPGRADE_ROLE_STARTED,
52
+ *     thenableWithCancel: Object
60 53
  * }
61 54
  */
62
-export const UPGRADE_ROLE_FAILED = Symbol('UPGRADE_ROLE_FAILED');
55
+export const UPGRADE_ROLE_STARTED = Symbol('UPGRADE_ROLE_STARTED');
63 56
 
64 57
 /**
65 58
  * The type of (redux) action that sets delayed handler which will check if
@@ -67,9 +60,9 @@ export const UPGRADE_ROLE_FAILED = Symbol('UPGRADE_ROLE_FAILED');
67 60
  * connection.
68 61
  *
69 62
  * {
70
- *      type: WAIT_FOR_OWNER,
71
- *      handler: Function,
72
- *      timeoutMs: number
63
+ *     type: WAIT_FOR_OWNER,
64
+ *     handler: Function,
65
+ *     timeoutMs: number
73 66
  * }
74 67
  */
75 68
 export const WAIT_FOR_OWNER = Symbol('WAIT_FOR_OWNER');

+ 81
- 118
react/features/authentication/actions.js Datei anzeigen

@@ -1,53 +1,57 @@
1
-import { openDialog } from '../base/dialog/actions';
2
-import { checkIfCanJoin } from '../base/conference/actions';
1
+/* @flow */
2
+
3
+import { checkIfCanJoin } from '../base/conference';
4
+import { openDialog } from '../base/dialog';
5
+
3 6
 import {
4 7
     CANCEL_LOGIN,
5 8
     CANCEL_WAIT_FOR_OWNER,
6 9
     STOP_WAIT_FOR_OWNER,
7
-    UPGRADE_ROLE_FAILED,
10
+    UPGRADE_ROLE_FINISHED,
8 11
     UPGRADE_ROLE_STARTED,
9
-    UPGRADE_ROLE_SUCCESS,
10 12
     WAIT_FOR_OWNER
11 13
 } from './actionTypes';
12 14
 import { LoginDialog, WaitForOwnerDialog } from './components';
13 15
 
16
+const logger = require('jitsi-meet-logger').getLogger(__filename);
17
+
14 18
 /**
15
- * Instantiates new {@link JitsiAuthConnection} and uses it to authenticate and
16
- * upgrade role of the current conference user to moderator which will allow to
17
- * create and join new conference on XMPP password + guest access configuration.
18
- * See {@link LoginDialog} description for more info.
19
+ * Initiates authenticating and upgrading the role of the local participant to
20
+ * moderator which will allow to create and join a new conference on an XMPP
21
+ * password + guest access configuration. Refer to {@link LoginDialog} for more
22
+ * info.
19 23
  *
20
- * @param {string} id - XMPP user's id eg. user@domain.com.
21
- * @param {string} userPassword - The user's password.
22
- * @param {JitsiConference} conference - The conference for which user's role
23
- * will be upgraded.
24
- * @returns {function({dispatch: Function, getState: Function})}
24
+ * @param {string} id - The XMPP user's ID (e.g. user@domain.com).
25
+ * @param {string} password - The XMPP user's password.
26
+ * @param {JitsiConference} conference - The conference for which the local
27
+ * participant's role will be upgraded.
28
+ * @returns {function({ dispatch: Dispatch, getState: Function })}
25 29
  */
26
-export function authenticateAndUpgradeRole(id, userPassword, conference) {
27
-    return (dispatch, getState) => {
28
-        const authConnection = conference.createAuthenticationConnection();
29
-
30
-        dispatch(_upgradeRoleStarted(authConnection));
31
-
30
+export function authenticateAndUpgradeRole(
31
+        id: string,
32
+        password: string,
33
+        conference: Object) {
34
+    return (dispatch: Dispatch, getState: Function) => {
32 35
         const { password: roomPassword }
33 36
             = getState()['features/base/conference'];
37
+        const process
38
+            = conference.authenticateAndUpgradeRole({
39
+                id,
40
+                password,
41
+                roomPassword
42
+            });
34 43
 
35
-        authConnection.authenticateAndUpgradeRole({
36
-            id,
37
-            password: userPassword,
38
-            roomPassword
39
-        })
40
-        .then(() => {
41
-            dispatch(_upgradeRoleSuccess());
42
-        })
43
-        .catch(error => {
44
-            // Lack of error means the operation was canceled, so no need to log
45
-            // that on error level.
46
-            if (error.error) {
47
-                console.error('upgradeRoleFailed', error);
48
-            }
49
-            dispatch(_upgradeRoleFailed(error));
50
-        });
44
+        dispatch(_upgradeRoleStarted(process));
45
+        process.then(
46
+            /* onFulfilled */ () => dispatch(_upgradeRoleFinished()),
47
+            /* onRejected */ error => {
48
+                // The lack of an error signals a cancellation.
49
+                if (error.authenticationError || error.connectionError) {
50
+                    logger.error('authenticateAndUpgradeRole failed', error);
51
+                }
52
+
53
+                dispatch(_upgradeRoleFinished(error));
54
+            });
51 55
     };
52 56
 }
53 57
 
@@ -55,7 +59,7 @@ export function authenticateAndUpgradeRole(id, userPassword, conference) {
55 59
  * Cancels {@ink LoginDialog}.
56 60
  *
57 61
  * @returns {{
58
- *      type: CANCEL_LOGIN
62
+ *     type: CANCEL_LOGIN
59 63
  * }}
60 64
  */
61 65
 export function cancelLogin() {
@@ -68,7 +72,7 @@ export function cancelLogin() {
68 72
  * Cancels {@link WaitForOwnerDialog}. Will navigate back to the welcome page.
69 73
  *
70 74
  * @returns {{
71
- *      type: CANCEL_WAIT_FOR_OWNER
75
+ *     type: CANCEL_WAIT_FOR_OWNER
72 76
  * }}
73 77
  */
74 78
 export function cancelWaitForOwner() {
@@ -78,118 +82,77 @@ export function cancelWaitForOwner() {
78 82
 }
79 83
 
80 84
 /**
81
- * Stops waiting for conference owner and clears any pending timeout.
82
- *
83
- * @returns {{
84
- *      type: STOP_WAIT_FOR_OWNER
85
- * }}
86
- */
87
-export function clearWaitForOwnerTimeout() {
88
-    return {
89
-        type: STOP_WAIT_FOR_OWNER
90
-    };
91
-}
92
-
93
-/**
94
- * Sets a delayed "wait for owner" handler function.
95
- *
96
- * @param {Function} handler - The "wait for owner" handler function.
97
- * @param {number} waitMs - The delay in milliseconds.
98
- *
99
- * @private
100
- * @returns {{
101
- *      type: WAIT_FOR_OWNER,
102
- *      handler: Function,
103
- *      timeoutMs: number
104
- * }}
105
- */
106
-function _setWaitForOwnerTimeout(handler, waitMs) {
107
-    return {
108
-        type: WAIT_FOR_OWNER,
109
-        handler,
110
-        timeoutMs: waitMs
111
-    };
112
-}
113
-
114
-/**
115
- * Displays {@link LoginDialog} which will ask to enter username and password
85
+ * Opens {@link LoginDialog} which will ask to enter username and password
116 86
  * for the current conference.
117 87
  *
118 88
  * @protected
119
- * @returns {{
120
- *     type: OPEN_DIALOG,
121
- *     component: LoginDialog,
122
- *     props: React.PropTypes
123
- * }}
89
+ * @returns {Action}
124 90
  */
125
-export function _showLoginDialog() {
126
-    return openDialog(LoginDialog, { });
91
+export function _openLoginDialog() {
92
+    return openDialog(LoginDialog);
127 93
 }
128 94
 
129 95
 /**
130
- * Displays {@link WaitForOnwerDialog}.
96
+ * Opens {@link WaitForOnwerDialog}.
131 97
  *
132 98
  * @protected
133
- * @returns {{
134
- *     type: OPEN_DIALOG,
135
- *     component: WaitForOwnerDialog,
136
- *     props: React.PropTypes
137
- * }}
99
+ * @returns {Action}
138 100
  */
139
-export function _showWaitForOwnerDialog() {
140
-    return openDialog(WaitForOwnerDialog, { });
101
+export function _openWaitForOwnerDialog() {
102
+    return openDialog(WaitForOwnerDialog);
141 103
 }
142 104
 
143 105
 /**
144
- * Emits an error which occurred during {@link authenticateAndUpgradeRole}.
106
+ * Stops waiting for the conference owner.
145 107
  *
146
- * @param {Object} error - Check the docs of {@link JitsiAuthConnection} in
147
- * lib-jitsi-meet for more details about the error's structure.
148
- *
149
- * @private
150 108
  * @returns {{
151
- *      type: UPGRADE_ROLE_FAILED,
152
- *      error: Object
109
+ *     type: STOP_WAIT_FOR_OWNER
153 110
  * }}
154 111
  */
155
-function _upgradeRoleFailed(error) {
112
+export function stopWaitForOwner() {
156 113
     return {
157
-        type: UPGRADE_ROLE_FAILED,
158
-        error
114
+        type: STOP_WAIT_FOR_OWNER
159 115
     };
160 116
 }
161 117
 
162 118
 /**
163
- * Signals that the role upgrade process has been started using given
164
- * {@link JitsiAuthConnection} instance.
165
- *
166
- * @param {JitsiAuthConnection} authenticationConnection - The authentication
167
- * connection instance that can be used to cancel the process.
119
+ * Signals that the process of authenticating and upgrading the local
120
+ * participant's role has finished either with success or with a specific error.
168 121
  *
122
+ * @param {Object} error - If <tt>undefined</tt>, then the process of
123
+ * authenticating and upgrading the local participant's role has succeeded;
124
+ * otherwise, it has failed with the specified error. Refer to
125
+ * {@link JitsiConference#authenticateAndUpgradeRole} in lib-jitsi-meet for the
126
+ * error details.
169 127
  * @private
170 128
  * @returns {{
171
- *      type: UPGRADE_ROLE_STARTED,
172
- *      authConnection: JitsiAuthConnection
129
+ *     type: UPGRADE_ROLE_FINISHED,
130
+ *     error: Object
173 131
  * }}
174 132
  */
175
-function _upgradeRoleStarted(authenticationConnection) {
133
+function _upgradeRoleFinished(error) {
176 134
     return {
177
-        type: UPGRADE_ROLE_STARTED,
178
-        authConnection: authenticationConnection
135
+        type: UPGRADE_ROLE_FINISHED,
136
+        error
179 137
     };
180 138
 }
181 139
 
182 140
 /**
183
- * Signals that the role upgrade process has been completed successfully.
141
+ * Signals that a process of authenticating and upgrading the local
142
+ * participant's role has started.
184 143
  *
144
+ * @param {Object} thenableWithCancel - The process of authenticating and
145
+ * upgrading the local participant's role.
185 146
  * @private
186 147
  * @returns {{
187
- *      type: UPGRADE_ROLE_SUCCESS
148
+ *     type: UPGRADE_ROLE_STARTED,
149
+ *     thenableWithCancel: Object
188 150
  * }}
189 151
  */
190
-function _upgradeRoleSuccess() {
152
+function _upgradeRoleStarted(thenableWithCancel) {
191 153
     return {
192
-        type: UPGRADE_ROLE_SUCCESS
154
+        type: UPGRADE_ROLE_STARTED,
155
+        thenableWithCancel
193 156
     };
194 157
 }
195 158
 
@@ -198,13 +161,13 @@ function _upgradeRoleSuccess() {
198 161
  * start the process of "waiting for the owner" by periodically trying to join
199 162
  * the room every five seconds.
200 163
  *
201
- * @returns {function({ dispatch: Function})}
164
+ * @returns {function({ dispatch: Dispatch })}
202 165
  */
203 166
 export function waitForOwner() {
204
-    return dispatch => {
205
-        dispatch(
206
-            _setWaitForOwnerTimeout(
207
-                () => dispatch(checkIfCanJoin()),
208
-                5000));
209
-    };
167
+    return (dispatch: Dispatch) =>
168
+        dispatch({
169
+            type: WAIT_FOR_OWNER,
170
+            handler: () => dispatch(checkIfCanJoin()),
171
+            timeoutMs: 5000
172
+        });
210 173
 }

+ 81
- 91
react/features/authentication/components/LoginDialog.native.js Datei anzeigen

@@ -1,22 +1,14 @@
1
+import PropTypes from 'prop-types';
1 2
 import React, { Component } from 'react';
3
+import { Text, TextInput, View } from 'react-native';
2 4
 import { connect as reduxConnect } from 'react-redux';
3
-import {
4
-    Button,
5
-    Modal,
6
-    Text,
7
-    TextInput,
8
-    View
9
-} from 'react-native';
10
-import {
11
-    authenticateAndUpgradeRole,
12
-    cancelLogin
13
-} from '../actions';
14
-import {
15
-    connect,
16
-    toJid
17
-} from '../../base/connection';
5
+
6
+import { connect, toJid } from '../../base/connection';
7
+import { Dialog } from '../../base/dialog';
18 8
 import { translate } from '../../base/i18n';
19 9
 import { JitsiConnectionErrors } from '../../base/lib-jitsi-meet';
10
+
11
+import { authenticateAndUpgradeRole, cancelLogin } from '../actions';
20 12
 import styles from './styles';
21 13
 
22 14
 /**
@@ -36,15 +28,15 @@ import styles from './styles';
36 28
  * yet, Jicofo will not allow to start new conference. This will trigger
37 29
  * 'CONFERENCE_FAILED' action with JitsiConferenceErrors.AUTHENTICATION_REQUIRED
38 30
  * error and 'authRequired' value of 'features/base/conference' will hold
39
- * the {@link JitsiConference} instance. If user decides to authenticate a new
40
- * {@link JitsiAuthConnection} will be created from which separate XMPP
41
- * connection is established and authentication is performed. In case it
42
- * succeeds Jicofo will assign new session ID which then can be used from
43
- * the anonymous domain connection to create and join the room. This part is
44
- * done by {@link JitsiAuthConnection} from lib-jitsi-meet.
31
+ * the {@link JitsiConference} instance. If user decides to authenticate, a
32
+ * new/separate XMPP connection is established and authentication is performed.
33
+ * In case it succeeds, Jicofo will assign new session ID which then can be used
34
+ * from the anonymous domain connection to create and join the room. This part
35
+ * is done by {@link JitsiConference#authenticateAndUpgradeRole} in
36
+ * lib-jitsi-meet.
45 37
  *
46
- * See https://github.com/jitsi/jicofo#secure-domain for configuration
47
- * parameters description.
38
+ * See {@link https://github.com/jitsi/jicofo#secure-domain} for a description
39
+ * of the configuration parameters.
48 40
  */
49 41
 class LoginDialog extends Component {
50 42
     /**
@@ -57,37 +49,37 @@ class LoginDialog extends Component {
57 49
          * {@link JitsiConference} that needs authentication - will hold a valid
58 50
          * value in XMPP login + guest access mode.
59 51
          */
60
-        conference: React.PropTypes.object,
52
+        _conference: PropTypes.object,
61 53
 
62 54
         /**
63 55
          *
64 56
          */
65
-        configHosts: React.PropTypes.object,
57
+        _configHosts: PropTypes.object,
66 58
 
67 59
         /**
68 60
          * Indicates if the dialog should display "connecting" status message.
69 61
          */
70
-        connecting: React.PropTypes.bool,
62
+        _connecting: PropTypes.bool,
71 63
 
72 64
         /**
73
-         * Redux store dispatch method.
65
+         * The error which occurred during login/authentication.
74 66
          */
75
-        dispatch: React.PropTypes.func,
67
+        _error: PropTypes.string,
76 68
 
77 69
         /**
78
-         * The error which occurred during login/authentication.
70
+         * Any extra details about the error provided by lib-jitsi-meet.
79 71
          */
80
-        error: React.PropTypes.string,
72
+        _errorDetails: PropTypes.string,
81 73
 
82 74
         /**
83
-         * Any extra details about the error provided by lib-jitsi-meet.
75
+         * Redux store dispatch method.
84 76
          */
85
-        errorDetails: React.PropTypes.string,
77
+        dispatch: PropTypes.func,
86 78
 
87 79
         /**
88 80
          * Invoked to obtain translated strings.
89 81
          */
90
-        t: React.PropTypes.func
82
+        t: PropTypes.func
91 83
     };
92 84
 
93 85
     /**
@@ -99,16 +91,16 @@ class LoginDialog extends Component {
99 91
     constructor(props) {
100 92
         super(props);
101 93
 
102
-        // Bind event handlers so they are only bound once for every instance.
103
-        this._onCancel = this._onCancel.bind(this);
104
-        this._onLogin = this._onLogin.bind(this);
105
-        this._onUsernameChange = this._onUsernameChange.bind(this);
106
-        this._onPasswordChange = this._onPasswordChange.bind(this);
107
-
108 94
         this.state = {
109 95
             username: '',
110 96
             password: ''
111 97
         };
98
+
99
+        // Bind event handlers so they are only bound once per instance.
100
+        this._onCancel = this._onCancel.bind(this);
101
+        this._onLogin = this._onLogin.bind(this);
102
+        this._onPasswordChange = this._onPasswordChange.bind(this);
103
+        this._onUsernameChange = this._onUsernameChange.bind(this);
112 104
     }
113 105
 
114 106
     /**
@@ -119,56 +111,51 @@ class LoginDialog extends Component {
119 111
      */
120 112
     render() {
121 113
         const {
122
-            error,
123
-            errorDetails,
124
-            connecting,
114
+            _connecting: connecting,
115
+            _error: error,
116
+            _errorDetails: errorDetails,
125 117
             t
126 118
         } = this.props;
127 119
 
128 120
         let messageKey = '';
129
-        const messageOptions = { };
121
+        const messageOptions = {};
130 122
 
131 123
         if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
132 124
             messageKey = 'dialog.incorrectPassword';
133 125
         } else if (error) {
134 126
             messageKey = 'dialog.connectErrorWithMsg';
135
-
136 127
             messageOptions.msg = `${error} ${errorDetails}`;
137 128
         }
138 129
 
139 130
         return (
140
-            <Modal
141
-                onRequestClose = { this._onCancel }
142
-                style = { styles.outerArea }
143
-                transparent = { true } >
144
-                <View style = { styles.dialogBox }>
145
-                    <Text>Username:</Text>
131
+            <Dialog
132
+                okDisabled = { connecting }
133
+                onCancel = { this._onCancel }
134
+                onSubmit = { this._onLogin }
135
+                titleKey = 'dialog.passwordRequired'>
136
+                <View style = { styles.loginDialog }>
146 137
                     <TextInput
147 138
                         onChangeText = { this._onUsernameChange }
148 139
                         placeholder = { 'user@domain.com' }
149
-                        style = { styles.textInput }
140
+                        style = { styles.loginDialogTextInput }
150 141
                         value = { this.state.username } />
151
-                    <Text>Password:</Text>
152 142
                     <TextInput
153 143
                         onChangeText = { this._onPasswordChange }
154 144
                         placeholder = { t('dialog.userPassword') }
155 145
                         secureTextEntry = { true }
156
-                        style = { styles.textInput }
146
+                        style = { styles.loginDialogTextInput }
157 147
                         value = { this.state.password } />
158
-                    <Text>
159
-                        {error ? t(messageKey, messageOptions) : ''}
160
-                        {connecting && !error
161
-                            ? t('connection.CONNECTING') : ''}
148
+                    <Text style = { styles.loginDialogText }>
149
+                        {
150
+                            error
151
+                                ? t(messageKey, messageOptions)
152
+                                : connecting
153
+                                    ? t('connection.CONNECTING')
154
+                                    : ''
155
+                        }
162 156
                     </Text>
163
-                    <Button
164
-                        disabled = { connecting }
165
-                        onPress = { this._onLogin }
166
-                        title = { t('dialog.Ok') } />
167
-                    <Button
168
-                        onPress = { this._onCancel }
169
-                        title = { t('dialog.Cancel') } />
170 157
                 </View>
171
-            </Modal>
158
+            </Dialog>
172 159
         );
173 160
     }
174 161
 
@@ -216,9 +203,9 @@ class LoginDialog extends Component {
216 203
      * @returns {void}
217 204
      */
218 205
     _onLogin() {
219
-        const conference = this.props.conference;
206
+        const { _conference: conference } = this.props;
220 207
         const { username, password } = this.state;
221
-        const jid = toJid(username, this.props.configHosts);
208
+        const jid = toJid(username, this.props._configHosts);
222 209
 
223 210
         // If there's a conference it means that the connection has succeeded,
224 211
         // but authentication is required in order to join the room.
@@ -238,42 +225,45 @@ class LoginDialog extends Component {
238 225
  * @param {Object} state - The Redux state.
239 226
  * @private
240 227
  * @returns {{
241
- *     configHosts: Object,
242
- *     connecting: boolean,
243
- *     error: string,
244
- *     errorDetails: string,
245
- *     conference: JitsiConference
228
+ *     _conference: JitsiConference,
229
+ *     _configHosts: Object,
230
+ *     _connecting: boolean,
231
+ *     _error: string,
232
+ *     _errorDetails: string
246 233
  * }}
247 234
  */
248 235
 function _mapStateToProps(state) {
236
+    const {
237
+        upgradeRoleError,
238
+        upgradeRoleInProgress
239
+    } = state['features/authentication'];
240
+    const { authRequired } = state['features/base/conference'];
249 241
     const { hosts: configHosts } = state['features/base/config'];
250 242
     const {
251 243
         connecting,
252 244
         error: connectionError,
253 245
         errorMessage: connectionErrorMessage
254 246
     } = state['features/base/connection'];
255
-    const {
256
-        authRequired
257
-    } = state['features/base/conference'];
258
-    const {
259
-        upgradeRoleError,
260
-        upgradeRoleInProgress
261
-    } = state['features/authentication'];
262 247
 
263
-    const error
264
-        = connectionError
265
-            || (upgradeRoleError
266
-                && (upgradeRoleError.connectionError
267
-                        || upgradeRoleError.authenticationError));
248
+    let error;
249
+    let errorDetails;
250
+
251
+    if (connectionError) {
252
+        error = connectionError;
253
+        errorDetails = connectionErrorMessage;
254
+    } else if (upgradeRoleError) {
255
+        error
256
+            = upgradeRoleError.connectionError
257
+                || upgradeRoleError.authenticationError;
258
+        errorDetails = upgradeRoleError.message;
259
+    }
268 260
 
269 261
     return {
270
-        configHosts,
271
-        connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress),
272
-        error,
273
-        errorDetails:
274
-            (connectionError && connectionErrorMessage)
275
-                || (upgradeRoleError && upgradeRoleError.message),
276
-        conference: authRequired
262
+        _conference: authRequired,
263
+        _configHosts: configHosts,
264
+        _connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress),
265
+        _error: error,
266
+        _errorDetails: errorDetails
277 267
     };
278 268
 }
279 269
 

+ 49
- 36
react/features/authentication/components/WaitForOwnerDialog.native.js Datei anzeigen

@@ -1,9 +1,12 @@
1
+import PropTypes from 'prop-types';
1 2
 import React, { Component } from 'react';
3
+import { Text } from 'react-native';
2 4
 import { connect } from 'react-redux';
3
-import { Button, Modal, Text, View } from 'react-native';
4 5
 
6
+import { Dialog } from '../../base/dialog';
5 7
 import { translate } from '../../base/i18n';
6
-import { _showLoginDialog, cancelWaitForOwner } from '../actions';
8
+
9
+import { cancelWaitForOwner, _openLoginDialog } from '../actions';
7 10
 import styles from './styles';
8 11
 
9 12
 /**
@@ -20,19 +23,19 @@ class WaitForOwnerDialog extends Component {
20 23
      */
21 24
     static propTypes = {
22 25
         /**
23
-         * Redux store dispatch function.
26
+         * The name of the conference room (without the domain part).
24 27
          */
25
-        dispatch: React.PropTypes.func,
28
+        _room: PropTypes.string,
26 29
 
27 30
         /**
28
-         * The name of the conference room (without the domain part).
31
+         * Redux store dispatch function.
29 32
          */
30
-        roomName: React.PropTypes.string,
33
+        dispatch: PropTypes.func,
31 34
 
32 35
         /**
33 36
          * Invoked to obtain translated strings.
34 37
          */
35
-        t: React.PropTypes.func
38
+        t: PropTypes.func
36 39
     };
37 40
 
38 41
     /**
@@ -44,8 +47,9 @@ class WaitForOwnerDialog extends Component {
44 47
     constructor(props) {
45 48
         super(props);
46 49
 
47
-        this._onLogin = this._onLogin.bind(this);
50
+        // Bind event handlers so they are only bound once per instance.
48 51
         this._onCancel = this._onCancel.bind(this);
52
+        this._onLogin = this._onLogin.bind(this);
49 53
     }
50 54
 
51 55
     /**
@@ -56,51 +60,60 @@ class WaitForOwnerDialog extends Component {
56 60
      */
57 61
     render() {
58 62
         const {
59
-            roomName,
63
+            _room: room,
60 64
             t
61 65
         } = this.props;
62 66
 
63 67
         return (
64
-            <Modal
65
-                onRequestClose = { this._onCancel }
66
-                style = { styles.outerArea }
67
-                transparent = { true } >
68
-                <View style = { styles.dialogBox } >
69
-                    <Text>
70
-                        { t(
71
-                            'dialog.WaitForHostMsg',
72
-                            { room: roomName })
73
-                        }
74
-                    </Text>
75
-                    <Button
76
-                        onPress = { this._onLogin }
77
-                        title = { t('dialog.IamHost') } />
78
-                    <Button
79
-                        onPress = { this._onCancel }
80
-                        title = { t('dialog.Cancel') } />
81
-                </View>
82
-            </Modal>
68
+            <Dialog
69
+                okTitleKey = { 'dialog.IamHost' }
70
+                onCancel = { this._onCancel }
71
+                onSubmit = { this._onLogin }
72
+                titleKey = 'dialog.WaitingForHost'>
73
+                <Text style = { styles.waitForOwnerDialog }>
74
+                    {
75
+                        this.renderHTML(t('dialog.WaitForHostMsg', { room }))
76
+                    }
77
+                </Text>
78
+            </Dialog>
83 79
         );
84 80
     }
85 81
 
86 82
     /**
87
-     * Called when the OK button is clicked.
83
+     * Called when the cancel button is clicked.
88 84
      *
89 85
      * @private
90 86
      * @returns {void}
91 87
      */
92
-    _onLogin() {
93
-        this.props.dispatch(_showLoginDialog());
88
+    _onCancel() {
89
+        this.props.dispatch(cancelWaitForOwner());
94 90
     }
95 91
 
96 92
     /**
97
-     * Called when the cancel button is clicked.
93
+     * Called when the OK button is clicked.
98 94
      *
99 95
      * @private
100 96
      * @returns {void}
101 97
      */
102
-    _onCancel() {
103
-        this.props.dispatch(cancelWaitForOwner());
98
+    _onLogin() {
99
+        this.props.dispatch(_openLoginDialog());
100
+    }
101
+
102
+    /**
103
+     * Renders a specific <tt>string</tt> which may contain HTML.
104
+     *
105
+     * @param {string} html - The <tt>string</tt> which may contain HTML to
106
+     * render.
107
+     * @returns {string}
108
+     */
109
+    _renderHTML(html) {
110
+        if (typeof html === 'string') {
111
+            // TODO Limited styling may easily be provided by utilizing Text
112
+            // with style.
113
+            return html.replace(/<\\?b>/gi, '');
114
+        }
115
+
116
+        return html;
104 117
     }
105 118
 }
106 119
 
@@ -111,7 +124,7 @@ class WaitForOwnerDialog extends Component {
111 124
  * @param {Object} state - The Redux state.
112 125
  * @private
113 126
  * @returns {{
114
- *     roomName: string
127
+ *     _room: string
115 128
  * }}
116 129
  */
117 130
 function _mapStateToProps(state) {
@@ -120,7 +133,7 @@ function _mapStateToProps(state) {
120 133
     } = state['features/base/conference'];
121 134
 
122 135
     return {
123
-        roomName: authRequired && authRequired.getName()
136
+        _room: authRequired && authRequired.getName()
124 137
     };
125 138
 }
126 139
 

+ 46
- 14
react/features/authentication/components/styles.js Datei anzeigen

@@ -1,23 +1,55 @@
1
-import {
2
-    ColorPalette,
3
-    createStyleSheet
4
-} from '../../base/styles';
1
+import { BoxModel, createStyleSheet } from '../../base/styles';
2
+
3
+/**
4
+ * The style common to <tt>LoginDialog</tt> and <tt>WaitForOwnerDialog</tt>.
5
+ */
6
+const dialog = {
7
+    marginBottom: BoxModel.margin,
8
+    marginTop: BoxModel.margin
9
+};
10
+
11
+/**
12
+ * The style common to <tt>Text</tt> rendered by <tt>LoginDialog</tt> and
13
+ * <tt>WaitForOwnerDialog</tt>.
14
+ */
15
+const text = {
16
+};
5 17
 
6 18
 /**
7 19
  * The styles of the authentication feature.
8 20
  */
9 21
 export default createStyleSheet({
10
-    outerArea: {
11
-        flex: 1
22
+    /**
23
+     * The style of <tt>LoginDialog</tt>.
24
+     */
25
+    loginDialog: {
26
+        ...dialog,
27
+        flex: 0,
28
+        flexDirection: 'column'
12 29
     },
13
-    dialogBox: {
14
-        marginLeft: '10%',
15
-        marginRight: '10%',
16
-        marginTop: '10%',
17
-        backgroundColor: ColorPalette.white
30
+
31
+    /**
32
+     * The style of <tt>Text</tt> rendered by <tt>LoginDialog</tt>.
33
+     */
34
+    loginDialogText: {
35
+        ...text
18 36
     },
19
-    textInput: {
20
-        height: 25,
21
-        fontSize: 16
37
+
38
+    /**
39
+     * The style of <tt>TextInput</tt> rendered by <tt>LoginDialog</tt>.
40
+     */
41
+    loginDialogTextInput: {
42
+        // XXX Matches react-native-prompt's dialogInput because base/dialog's
43
+        // Dialog is implemented using react-native-prompt.
44
+        fontSize: 18,
45
+        height: 50
46
+    },
47
+
48
+    /**
49
+     * The style of <tt>WaitForOwnerDialog</tt>.
50
+     */
51
+    waitForOwnerDialog: {
52
+        ...dialog,
53
+        ...text
22 54
     }
23 55
 });

+ 0
- 74
react/features/authentication/functions.js Datei anzeigen

@@ -1,74 +0,0 @@
1
-import {
2
-    LoginDialog,
3
-    WaitForOwnerDialog
4
-} from './components/index';
5
-import { hideDialog } from '../base/dialog/actions';
6
-
7
-/**
8
- * Will clear the wait for conference owner timeout handler if any is currently
9
- * set.
10
- *
11
- * @param {Object} store - The Redux store instance.
12
- * @returns {void}
13
- */
14
-export function clearExistingWaitForOwnerTimeout(store) {
15
-    const { waitForOwnerTimeoutID }
16
-        = store.getState()['features/authentication'];
17
-
18
-    if (waitForOwnerTimeoutID) {
19
-        clearTimeout(waitForOwnerTimeoutID);
20
-    }
21
-}
22
-
23
-/**
24
- * Checks if {@link LoginDialog} is currently open.
25
- *
26
- * @param {Object|Function} getStateOrState - The Redux store instance or
27
- * store's get state method.
28
- * @returns {boolean}
29
- */
30
-export function isLoginDialogOpened(getStateOrState) {
31
-    const state
32
-        = typeof getStateOrState === 'function'
33
-            ? getStateOrState() : getStateOrState;
34
-    const dialogState = state['features/base/dialog'];
35
-
36
-    return dialogState.component && dialogState.component === LoginDialog;
37
-}
38
-
39
-/**
40
- * Hides {@link LoginDialog} if it's currently displayed.
41
- *
42
- * @param {Object} store - The Redux store instance.
43
- * @returns {void}
44
- */
45
-export function hideLoginDialog({ dispatch, getState }) {
46
-    if (isLoginDialogOpened(getState)) {
47
-        dispatch(hideDialog());
48
-    }
49
-}
50
-
51
-/**
52
- * Checks if {@link WaitForOwnerDialog} is currently open.
53
- *
54
- * @param {Object} store - The Redux store instance.
55
- * @returns {boolean}
56
- */
57
-export function isWaitForOwnerDialogOpened({ getState }) {
58
-    const dialogState = getState()['features/base/dialog'];
59
-
60
-    return dialogState.component
61
-        && dialogState.component === WaitForOwnerDialog;
62
-}
63
-
64
-/**
65
- * Checks if the cyclic "wait for conference owner" task is currently scheduled.
66
- *
67
- * @param {Object} store - The Redux store instance.
68
- * @returns {boolean}
69
- */
70
-export function isWaitingForOwner({ getState }) {
71
-    const { waitForOwnerTimeoutID } = getState()['features/authentication'];
72
-
73
-    return Boolean(waitForOwnerTimeoutID);
74
-}

+ 1
- 2
react/features/authentication/index.js Datei anzeigen

@@ -1,7 +1,6 @@
1 1
 export * from './actions';
2 2
 export * from './actionTypes';
3
-export * from './functions';
3
+export * from './components';
4 4
 
5 5
 import './middleware';
6
-
7 6
 import './reducer';

+ 109
- 88
react/features/authentication/middleware.js Datei anzeigen

@@ -1,40 +1,33 @@
1
+import { appNavigate } from '../app';
2
+import {
3
+    CONFERENCE_FAILED,
4
+    CONFERENCE_JOINED,
5
+    CONFERENCE_LEFT
6
+} from '../base/conference';
7
+import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection';
8
+import { hideDialog, isDialogOpen } from '../base/dialog';
9
+import {
10
+    JitsiConferenceErrors,
11
+    JitsiConnectionErrors
12
+} from '../base/lib-jitsi-meet';
1 13
 import { MiddlewareRegistry } from '../base/redux';
2 14
 
3 15
 import {
4
-    clearWaitForOwnerTimeout,
5
-    _showLoginDialog,
6
-    _showWaitForOwnerDialog,
16
+    _openLoginDialog,
17
+    _openWaitForOwnerDialog,
18
+    stopWaitForOwner,
7 19
     waitForOwner
8 20
 } from './actions';
9
-import { appNavigate } from '../app/actions';
10 21
 import {
11 22
     CANCEL_LOGIN,
12 23
     CANCEL_WAIT_FOR_OWNER,
13 24
     STOP_WAIT_FOR_OWNER,
14 25
     WAIT_FOR_OWNER
15 26
 } from './actionTypes';
16
-import {
17
-    CONFERENCE_FAILED,
18
-    CONFERENCE_JOINED,
19
-    CONFERENCE_LEFT
20
-} from '../base/conference/actionTypes';
21
-import { hideDialog } from '../base/dialog/actions';
22
-import { CONNECTION_ESTABLISHED } from '../base/connection/actionTypes';
23
-import { CONNECTION_FAILED } from '../base/connection';
24
-import {
25
-    clearExistingWaitForOwnerTimeout,
26
-    hideLoginDialog,
27
-    isLoginDialogOpened,
28
-    isWaitForOwnerDialogOpened,
29
-    isWaitingForOwner
30
-} from './functions';
31
-import {
32
-    JitsiConferenceErrors,
33
-    JitsiConnectionErrors
34
-} from '../base/lib-jitsi-meet';
27
+import { LoginDialog, WaitForOwnerDialog } from './components';
35 28
 
36 29
 /**
37
- * Middleware that captures connection or conference failed errors and controlls
30
+ * Middleware that captures connection or conference failed errors and controls
38 31
  * {@link WaitForOwnerDialog} and {@link LoginDialog}.
39 32
  *
40 33
  * FIXME Some of the complexity was introduced by the lack of dialog stacking.
@@ -44,93 +37,121 @@ import {
44 37
  */
45 38
 MiddlewareRegistry.register(store => next => action => {
46 39
     switch (action.type) {
47
-    case CONNECTION_FAILED: {
48
-        if (action.error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
49
-            store.dispatch(_showLoginDialog());
40
+    case CANCEL_LOGIN: {
41
+        const { upgradeRoleInProgress }
42
+            = store.getState()['features/authentication'];
43
+
44
+        upgradeRoleInProgress && upgradeRoleInProgress.cancel();
45
+
46
+        // The LoginDialog can be opened on top of "wait for owner". The app
47
+        // should navigate only if LoginDialog was open without the
48
+        // WaitForOwnerDialog.
49
+        if (!isDialogOpen(store, WaitForOwnerDialog)) {
50
+            if (_isWaitingForOwner(store)) {
51
+                // Instead of hiding show the new one.
52
+                const result = next(action);
53
+
54
+                store.dispatch(_openWaitForOwnerDialog());
55
+
56
+                return result;
57
+            }
58
+
59
+            // Go back to the app's entry point.
60
+            _hideLoginDialog(store);
61
+            store.dispatch(appNavigate(undefined));
50 62
         }
51 63
         break;
52 64
     }
53
-    case CONNECTION_ESTABLISHED: {
54
-        hideLoginDialog(store);
55
-        break;
65
+
66
+    case CANCEL_WAIT_FOR_OWNER: {
67
+        const result = next(action);
68
+
69
+        store.dispatch(stopWaitForOwner());
70
+        store.dispatch(appNavigate(undefined));
71
+
72
+        return result;
56 73
     }
57
-    case CONFERENCE_FAILED: {
74
+
75
+    case CONFERENCE_FAILED:
58 76
         if (action.error === JitsiConferenceErrors.AUTHENTICATION_REQUIRED) {
59 77
             store.dispatch(waitForOwner());
60 78
         } else {
61
-            store.dispatch(clearWaitForOwnerTimeout());
79
+            store.dispatch(stopWaitForOwner());
62 80
         }
63 81
         break;
64
-    }
65
-    case CONFERENCE_JOINED: {
66
-        if (isWaitingForOwner(store)) {
67
-            store.dispatch(clearWaitForOwnerTimeout());
82
+
83
+    case CONFERENCE_JOINED:
84
+        if (_isWaitingForOwner(store)) {
85
+            store.dispatch(stopWaitForOwner());
68 86
         }
69
-        hideLoginDialog(store);
70
-        break;
71
-    }
72
-    case CONFERENCE_LEFT: {
73
-        store.dispatch(clearWaitForOwnerTimeout());
87
+        _hideLoginDialog(store);
74 88
         break;
75
-    }
76
-    case WAIT_FOR_OWNER: {
77
-        clearExistingWaitForOwnerTimeout(store);
78
-        const { handler, timeoutMs } = action;
79
-        const newTimeoutId = setTimeout(handler, timeoutMs);
80 89
 
81
-        action.waitForOwnerTimeoutID = newTimeoutId;
90
+    case CONFERENCE_LEFT:
91
+        store.dispatch(stopWaitForOwner());
92
+        break;
82 93
 
83
-        // The WAIT_FOR_OWNER action is cyclic and we don't want to hide
84
-        // the login dialog every few seconds...
85
-        if (!isLoginDialogOpened(store.getState())) {
86
-            store.dispatch(_showWaitForOwnerDialog());
87
-        }
94
+    case CONNECTION_ESTABLISHED:
95
+        _hideLoginDialog(store);
88 96
         break;
89
-    }
90
-    case STOP_WAIT_FOR_OWNER: {
91
-        clearExistingWaitForOwnerTimeout(store);
92
-        if (isWaitForOwnerDialogOpened(store)) {
93
-            store.dispatch(hideDialog());
94
-        }
97
+
98
+    case CONNECTION_FAILED:
99
+        action.error === JitsiConnectionErrors.PASSWORD_REQUIRED
100
+            && store.dispatch(_openLoginDialog());
95 101
         break;
96
-    }
97
-    case CANCEL_LOGIN: {
98
-        const { upgradeRoleInProgress }
99
-            = store.getState()['features/authentication'];
100 102
 
101
-        if (upgradeRoleInProgress) {
102
-            upgradeRoleInProgress.cancel();
103
-        }
103
+    case STOP_WAIT_FOR_OWNER:
104
+        _clearExistingWaitForOwnerTimeout(store);
105
+        store.dispatch(hideDialog(WaitForOwnerDialog));
106
+        break;
104 107
 
105
-        const waitingForOwner = isWaitingForOwner(store);
108
+    case WAIT_FOR_OWNER: {
109
+        _clearExistingWaitForOwnerTimeout(store);
106 110
 
107
-        // The LoginDialog can be opened on top of "wait for owner". The app
108
-        // should navigate only if LoginDialog was open without
109
-        // the WaitForOwnerDialog.
110
-        if (!isWaitForOwnerDialogOpened(store) && !waitingForOwner) {
111
-            // Go back to app entry point
112
-            hideLoginDialog(store);
113
-            store.dispatch(appNavigate(undefined));
114
-        } else if (!isWaitForOwnerDialogOpened(store) && waitingForOwner) {
115
-            // Instead of hiding show the new one.
116
-            const result = next(action);
111
+        const { handler, timeoutMs } = action;
117 112
 
118
-            store.dispatch(_showWaitForOwnerDialog());
113
+        action.waitForOwnerTimeoutID = setTimeout(handler, timeoutMs);
119 114
 
120
-            return result;
121
-        }
115
+        // The WAIT_FOR_OWNER action is cyclic and we don't want to hide the
116
+        // login dialog every few seconds...
117
+        isDialogOpen(store, LoginDialog)
118
+            || store.dispatch(_openWaitForOwnerDialog());
122 119
         break;
123 120
     }
124
-    case CANCEL_WAIT_FOR_OWNER: {
125
-        const result = next(action);
126
-
127
-        store.dispatch(clearWaitForOwnerTimeout());
128
-        store.dispatch(appNavigate(undefined));
129
-
130
-        return result;
131
-    }
132
-
133 121
     }
134 122
 
135 123
     return next(action);
136 124
 });
125
+
126
+/**
127
+ * Will clear the wait for conference owner timeout handler if any is currently
128
+ * set.
129
+ *
130
+ * @param {Object} store - The redux store.
131
+ * @returns {void}
132
+ */
133
+function _clearExistingWaitForOwnerTimeout({ getState }) {
134
+    const { waitForOwnerTimeoutID } = getState()['features/authentication'];
135
+
136
+    waitForOwnerTimeoutID && clearTimeout(waitForOwnerTimeoutID);
137
+}
138
+
139
+/**
140
+ * Hides {@link LoginDialog} if it's currently displayed.
141
+ *
142
+ * @param {Object} store - The redux store.
143
+ * @returns {void}
144
+ */
145
+function _hideLoginDialog({ dispatch }) {
146
+    dispatch(hideDialog(LoginDialog));
147
+}
148
+
149
+/**
150
+ * Checks if the cyclic "wait for conference owner" task is currently scheduled.
151
+ *
152
+ * @param {Object} store - The redux store.
153
+ * @returns {boolean}
154
+ */
155
+function _isWaitingForOwner({ getState }) {
156
+    return Boolean(getState()['features/authentication'].waitForOwnerTimeoutID);
157
+}

+ 18
- 22
react/features/authentication/reducer.js Datei anzeigen

@@ -1,43 +1,39 @@
1
-import { assign } from '../base/redux/functions';
2
-import { ReducerRegistry } from '../base/redux';
1
+/* @flow */
2
+
3
+import { assign, ReducerRegistry } from '../base/redux';
3 4
 
4 5
 import {
5 6
     CANCEL_LOGIN,
6 7
     STOP_WAIT_FOR_OWNER,
7
-    UPGRADE_ROLE_FAILED, UPGRADE_ROLE_STARTED, UPGRADE_ROLE_SUCCESS,
8
+    UPGRADE_ROLE_FINISHED,
9
+    UPGRADE_ROLE_STARTED,
8 10
     WAIT_FOR_OWNER
9 11
 } from './actionTypes';
10 12
 
11
-ReducerRegistry.register('features/authentication', (state = { }, action) => {
13
+ReducerRegistry.register('features/authentication', (state = {}, action) => {
12 14
     switch (action.type) {
13
-    case WAIT_FOR_OWNER:
14
-        return assign(state, {
15
-            waitForOwnerTimeoutID: action.waitForOwnerTimeoutID
16
-        });
17
-    case UPGRADE_ROLE_STARTED:
15
+    case CANCEL_LOGIN:
18 16
         return assign(state, {
19 17
             upgradeRoleError: undefined,
20
-            upgradeRoleInProgress: action.authConnection
18
+            upgradeRoleInProgress: undefined
21 19
         });
22
-    case UPGRADE_ROLE_SUCCESS:
20
+
21
+    case STOP_WAIT_FOR_OWNER:
23 22
         return assign(state, {
24 23
             upgradeRoleError: undefined,
25
-            upgradeRoleInProgress: undefined
24
+            waitForOwnerTimeoutID: undefined
26 25
         });
27
-    case UPGRADE_ROLE_FAILED:
26
+
27
+    case UPGRADE_ROLE_FINISHED:
28
+    case UPGRADE_ROLE_STARTED:
28 29
         return assign(state, {
29 30
             upgradeRoleError: action.error,
30
-            upgradeRoleInProgress: undefined
31
+            upgradeRoleInProgress: action.thenableWithCancel
31 32
         });
32
-    case CANCEL_LOGIN:
33
-        return assign(state, {
34
-            upgradeRoleError: undefined,
35
-            upgradeRoleInProgress: undefined
36
-        });
37
-    case STOP_WAIT_FOR_OWNER:
33
+
34
+    case WAIT_FOR_OWNER:
38 35
         return assign(state, {
39
-            waitForOwnerTimeoutID: undefined,
40
-            upgradeRoleError: undefined
36
+            waitForOwnerTimeoutID: action.waitForOwnerTimeoutID
41 37
         });
42 38
     }
43 39
 

+ 2
- 4
react/features/base/conference/actions.js Datei anzeigen

@@ -298,12 +298,10 @@ export function createConference() {
298 298
  */
299 299
 export function checkIfCanJoin() {
300 300
     return (dispatch, getState) => {
301
-        const { password, authRequired }
301
+        const { authRequired, password }
302 302
             = getState()['features/base/conference'];
303 303
 
304
-        if (authRequired) {
305
-            authRequired.join(password);
306
-        }
304
+        authRequired && authRequired.join(password);
307 305
     };
308 306
 }
309 307
 

+ 4
- 5
react/features/base/connection/actions.native.js Datei anzeigen

@@ -18,12 +18,11 @@ import {
18 18
 /**
19 19
  * Opens new connection.
20 20
  *
21
- * @param {string} [username] - The XMPP user id eg. user@server.com.
22
- * @param {string} [password] - The user's password.
23
- *
21
+ * @param {string} [id] - The XMPP user's ID (e.g. user@server.com).
22
+ * @param {string} [password] - The XMPP user's password.
24 23
  * @returns {Function}
25 24
  */
26
-export function connect(username: ?string, password: ?string) {
25
+export function connect(id: ?string, password: ?string) {
27 26
     return (dispatch: Dispatch<*>, getState: Function) => {
28 27
         const state = getState();
29 28
         const options = _constructOptions(state);
@@ -47,7 +46,7 @@ export function connect(username: ?string, password: ?string) {
47 46
             _onConnectionFailed);
48 47
 
49 48
         connection.connect({
50
-            id: username,
49
+            id,
51 50
             password
52 51
         });
53 52
 

+ 7
- 17
react/features/base/connection/functions.js Datei anzeigen

@@ -53,24 +53,14 @@ export function getURLWithoutParams(url: URL): URL {
53 53
 }
54 54
 
55 55
 /**
56
- * Convert provided id to jid if it's not jid yet.
56
+ * Converts a specific id to jid if it's not jid yet.
57 57
  *
58 58
  * @param {string} id - User id or jid.
59
- * @param {Object} configHosts - The 'hosts' part of the config object.
60
- * @returns {string} jid - A string in the form of user@server.com.
59
+ * @param {Object} configHosts - The <tt>hosts</tt> part of the <tt>config</tt>
60
+ * object.
61
+ * @returns {string} A string in the form of a JID (i.e.
62
+ * <tt>user@server.com</tt>).
61 63
  */
62
-export function toJid(id: string, configHosts: Object): string {
63
-    if (id.indexOf('@') >= 0) {
64
-        return id;
65
-    }
66
-
67
-    let jid = id.concat('@');
68
-
69
-    if (configHosts.authdomain) {
70
-        jid += configHosts.authdomain;
71
-    } else {
72
-        jid += configHosts.domain;
73
-    }
74
-
75
-    return jid;
64
+export function toJid(id: string, { authdomain, domain }: Object): string {
65
+    return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
76 66
 }

Laden…
Abbrechen
Speichern