Skip to content

Commit bf7d40a

Browse files
committed
TF-4081 Auto re-login with user email on 401 error for mobile
1 parent 7710b58 commit bf7d40a

File tree

6 files changed

+67
-19
lines changed

6 files changed

+67
-19
lines changed

lib/features/base/base_controller.dart

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions
2525
import 'package:tmail_ui_user/features/login/data/network/config/oidc_constant.dart';
2626
import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart';
2727
import 'package:tmail_ui_user/features/login/domain/exceptions/logout_exception.dart';
28+
import 'package:tmail_ui_user/features/login/domain/model/login_source.dart';
2829
import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart';
2930
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
3031
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
32+
import 'package:tmail_ui_user/features/login/presentation/model/auto_refresh_arguments.dart';
3133
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
3234
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/contact_autocomplete_bindings.dart';
3335
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/tmail_autocomplete_bindings.dart';
@@ -195,10 +197,12 @@ abstract class BaseController extends GetxController
195197
}
196198
}
197199

198-
Future<void> _executeBeforeReconnectAndLogOut() async {
200+
Future<void> _executeBeforeReconnectAndLogOut({
201+
LoginSource source = LoginSource.manual,
202+
}) async {
199203
twakeAppManager.setExecutingBeforeReconnect(true);
200204
await executeBeforeReconnect();
201-
clearDataAndGoToLoginPage();
205+
clearDataAndGoToLoginPage(source: source);
202206
}
203207

204208
void onCancelReconnectWhenSessionExpired() {}
@@ -229,9 +233,9 @@ abstract class BaseController extends GetxController
229233
void handleBadCredentialsException() {
230234
log('$runtimeType::handleBadCredentialsException:');
231235
if (twakeAppManager.hasComposer) {
232-
_performSaveAndReconnection();
236+
_performSaveAndReconnection(source: LoginSource.auto);
233237
} else {
234-
_performReconnection();
238+
_performReconnection(source: LoginSource.auto);
235239
}
236240
}
237241

@@ -250,16 +254,20 @@ abstract class BaseController extends GetxController
250254
}
251255
}
252256

253-
void _performSaveAndReconnection() {
257+
void _performSaveAndReconnection({
258+
LoginSource source = LoginSource.manual,
259+
}) {
254260
if (PlatformInfo.isWeb) {
255-
_executeBeforeReconnectAndLogOut();
261+
_executeBeforeReconnectAndLogOut(source: source);
256262
} else if (PlatformInfo.isMobile) {
257-
clearDataAndGoToLoginPage();
263+
clearDataAndGoToLoginPage(source: source);
258264
}
259265
}
260266

261-
void _performReconnection() {
262-
clearDataAndGoToLoginPage();
267+
void _performReconnection({
268+
LoginSource source = LoginSource.manual,
269+
}) {
270+
clearDataAndGoToLoginPage(source: source);
263271
}
264272

265273
void onDataFailureViewState(Failure failure) {
@@ -420,9 +428,24 @@ abstract class BaseController extends GetxController
420428
}
421429
}
422430

423-
void removeAllPageAndGoToLogin() {
431+
void removeAllPageAndGoToLogin({
432+
LoginSource source = LoginSource.manual,
433+
}) {
424434
if (PlatformInfo.isMobile) {
425-
pushAndPopAll(AppRoutes.twakeWelcome);
435+
final jmapUrl = dynamicUrlInterceptors.jmapUrl ?? '';
436+
437+
final isAutoRefresh = source == LoginSource.auto &&
438+
Get.currentRoute != AppRoutes.login &&
439+
jmapUrl.isNotEmpty;
440+
441+
if (isAutoRefresh) {
442+
pushAndPopAll(
443+
AppRoutes.login,
444+
arguments: AutoRefreshArguments(jmapUrl),
445+
);
446+
} else {
447+
pushAndPopAll(AppRoutes.twakeWelcome);
448+
}
426449
} else {
427450
navigateToLoginPage();
428451
}
@@ -564,10 +587,12 @@ abstract class BaseController extends GetxController
564587
await beforeReconnectManager?.executeBeforeReconnectListeners();
565588
}
566589

567-
Future<void> clearDataAndGoToLoginPage() async {
568-
log('$runtimeType::clearDataAndGoToLoginPage:');
590+
Future<void> clearDataAndGoToLoginPage({
591+
LoginSource source = LoginSource.manual,
592+
}) async {
593+
log('$runtimeType::clearDataAndGoToLoginPage: Login source is $source');
569594
await clearAllData();
570-
removeAllPageAndGoToLogin();
595+
removeAllPageAndGoToLogin(source: source);
571596
}
572597

573598
Future<void> clearAllData() async {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
enum LoginSource {
2+
manual, // User manually logs in
3+
auto // Auto retry after 401
4+
}

lib/features/login/presentation/login_controller.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import 'package:tmail_ui_user/features/login/domain/usecases/try_guessing_web_fi
5353
import 'package:tmail_ui_user/features/login/presentation/extensions/generate_oidc_guessing_urls.dart';
5454
import 'package:tmail_ui_user/features/login/presentation/extensions/handle_openid_configuration.dart';
5555
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
56+
import 'package:tmail_ui_user/features/login/presentation/model/auto_refresh_arguments.dart';
5657
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
5758
import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_twake_workplace_state.dart';
5859
import 'package:tmail_ui_user/features/starting_page/domain/usecase/sign_in_twake_workplace_interactor.dart';
@@ -140,6 +141,8 @@ class LoginController extends ReloadableController {
140141
if (PlatformInfo.isWeb) {
141142
_checkOIDCIsAvailable();
142143
}
144+
} else if (arguments is AutoRefreshArguments) {
145+
_handleDNSLookupToGetJmapUrlSuccess(arguments.jmapUrl);
143146
} else if (PlatformInfo.isWeb) {
144147
_getAuthenticationInfo();
145148
}
@@ -194,7 +197,7 @@ class LoginController extends ReloadableController {
194197
} else if (success is AuthenticationUserSuccess) {
195198
_loginSuccessAction(success);
196199
} else if (success is DNSLookupToGetJmapUrlSuccess) {
197-
_handleDNSLookupToGetJmapUrlSuccess(success);
200+
_handleDNSLookupToGetJmapUrlSuccess(success.jmapUrl);
198201
} else if (success is TryGuessingWebFingerSuccess) {
199202
onBaseUrlChange(success.oidcResponse.subject);
200203
getOIDCConfiguration(success.oidcResponse);
@@ -542,8 +545,8 @@ class LoginController extends ReloadableController {
542545
}
543546
}
544547

545-
void _handleDNSLookupToGetJmapUrlSuccess(DNSLookupToGetJmapUrlSuccess success) {
546-
onBaseUrlChange(success.jmapUrl);
548+
void _handleDNSLookupToGetJmapUrlSuccess(String jmapUrl) {
549+
onBaseUrlChange(jmapUrl);
547550
_checkOIDCIsAvailable();
548551
}
549552

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import 'package:tmail_ui_user/main/routes/router_arguments.dart';
2+
3+
class AutoRefreshArguments extends RouterArguments {
4+
final String jmapUrl;
5+
6+
AutoRefreshArguments(this.jmapUrl);
7+
8+
@override
9+
List<Object?> get props => [jmapUrl];
10+
}

lib/main/exceptions/remote_exception_thrower.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:io';
22

33
import 'package:core/utils/app_logger.dart';
4+
import 'package:core/utils/platform_info.dart';
45
import 'package:dio/dio.dart';
56
import 'package:get/get_connect/http/src/status/http_status.dart';
67
import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart';
@@ -30,16 +31,21 @@ class RemoteExceptionThrower extends ExceptionThrower {
3031
}
3132

3233
void handleDioError(dynamic error) {
34+
logError('RemoteExceptionThrower::handleDioError(): ${error.runtimeType}');
3335
if (error is ChainedRequestError) {
3436
final statusCode = error.primaryError.response?.statusCode;
3537
final secondaryError = error.secondaryError;
36-
if (statusCode == HttpStatus.unauthorized && secondaryError != null) {
38+
if (PlatformInfo.isMobile &&
39+
statusCode == HttpStatus.unauthorized &&
40+
secondaryError != null) {
3741
throw ClientAuthenticationException(
3842
code: HttpStatus.unauthorized,
3943
secondErrorCode: getCodeByError(secondaryError),
4044
message: getMessageByError(secondaryError),
4145
);
4246
}
47+
48+
error = error.primaryError.copyWith(error: secondaryError);
4349
}
4450

4551
if (error is DioError) {

lib/main/utils/toast_manager.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class ToastManager {
149149
exception,
150150
useDefaultMessage: true,
151151
);
152-
} else if (_isEmptySpamFolderFailure(exception)) {
152+
} else if (_isEmptySpamFolderFailure(failure)) {
153153
message = message ?? AppLocalizations.of(context).emptySpamFolderFailed;
154154
} else if (_isEmptyTrashFolderFailure(failure)) {
155155
message = message ?? AppLocalizations.of(context).emptyTrashFolderFailed;

0 commit comments

Comments
 (0)