From 4cff46623c1f8744aa14f840120a746f10a5ce91 Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 22 Jun 2022 11:26:43 +0700 Subject: [PATCH] TF-196 Implement RemoteExceptionThrower when get session --- .../network/remote_exception_thrower.dart | 15 ++++++-- .../domain/exceptions/remote_exception.dart | 13 +++++-- .../exceptions/authentication_exception.dart | 23 ++++++++---- .../usecases/get_credential_interactor.dart | 2 +- .../get_stored_token_oidc_interactor.dart | 2 +- .../session_datasource_impl.dart | 23 +++++++++--- .../presentation/session_controller.dart | 36 +++++++++++++++++-- .../presentation/session_page_bindings.dart | 2 ++ lib/l10n/intl_messages.arb | 8 ++++- .../bindings/network/network_bindings.dart | 5 +++ .../bindings/session/session_bindings.dart | 10 +++--- lib/main/localizations/app_localizations.dart | 5 +++ 12 files changed, 117 insertions(+), 27 deletions(-) diff --git a/core/lib/data/network/remote_exception_thrower.dart b/core/lib/data/network/remote_exception_thrower.dart index 9b9e8f9e0..3074d9980 100644 --- a/core/lib/data/network/remote_exception_thrower.dart +++ b/core/lib/data/network/remote_exception_thrower.dart @@ -5,9 +5,20 @@ import 'package:dio/dio.dart'; class RemoteExceptionThrower { void throwRemoteException(dynamic exception, {Function(DioError)? handler}) { if (exception is DioError) { - handler != null ? handler(exception) : throw UnknownError(exception.message); + switch (exception.type) { + case DioErrorType.connectTimeout: + throw ConnectError(); + default: + if (handler != null) { + throw handler(exception); + } else { + throw UnknownError( + code: exception.response?.statusCode, + message: exception.message); + } + } } else { - throw UnknownError(exception.toString()); + throw UnknownError(message: exception.toString()); } } } diff --git a/core/lib/domain/exceptions/remote_exception.dart b/core/lib/domain/exceptions/remote_exception.dart index 3d3b0f7d9..1bbdb35d7 100644 --- a/core/lib/domain/exceptions/remote_exception.dart +++ b/core/lib/domain/exceptions/remote_exception.dart @@ -2,14 +2,23 @@ import 'package:equatable/equatable.dart'; abstract class RemoteException extends Equatable implements Exception { + static final connectError = 'Connect error'; final String? message; + final int? code; - RemoteException(this.message); + RemoteException({this.code, this.message}); } class UnknownError extends RemoteException { - UnknownError(String? message) : super(message); + UnknownError({int? code, String? message}) : super(code: code, message: message); + + @override + List get props => []; +} + +class ConnectError extends RemoteException { + ConnectError() : super(message: RemoteException.connectError); @override List get props => []; diff --git a/lib/features/login/domain/exceptions/authentication_exception.dart b/lib/features/login/domain/exceptions/authentication_exception.dart index 7c0ff3bea..c3c960830 100644 --- a/lib/features/login/domain/exceptions/authentication_exception.dart +++ b/lib/features/login/domain/exceptions/authentication_exception.dart @@ -1,17 +1,26 @@ -import 'package:equatable/equatable.dart'; -abstract class AuthenticationException extends Equatable { +import 'package:core/domain/exceptions/remote_exception.dart'; + +abstract class AuthenticationException extends RemoteException { static const wrongCredential = 'Credential is wrong'; + static const badGateway = 'Bad gateway'; static const invalidBaseUrl = 'Invalid base URL'; - const AuthenticationException(String message); + AuthenticationException(String message) : super(message: message); } class BadCredentials extends AuthenticationException { - const BadCredentials() : super(AuthenticationException.wrongCredential); + BadCredentials() : super(AuthenticationException.wrongCredential); @override - List get props => []; + List get props => [message]; +} + +class BadGateway extends AuthenticationException { + BadGateway() : super(AuthenticationException.badGateway); + + @override + List get props => [message]; } class NotFoundAuthenticatedAccountException implements Exception { @@ -23,10 +32,10 @@ class NotFoundStoredTokenException implements Exception { } class InvalidBaseUrl extends AuthenticationException { - const InvalidBaseUrl() : super(AuthenticationException.invalidBaseUrl); + InvalidBaseUrl() : super(AuthenticationException.invalidBaseUrl); @override - List get props => []; + List get props => [message]; } class NotFoundAccessTokenException implements Exception { diff --git a/lib/features/login/domain/usecases/get_credential_interactor.dart b/lib/features/login/domain/usecases/get_credential_interactor.dart index 37a266cd2..d320865d2 100644 --- a/lib/features/login/domain/usecases/get_credential_interactor.dart +++ b/lib/features/login/domain/usecases/get_credential_interactor.dart @@ -20,7 +20,7 @@ class GetCredentialInteractor { if (isCredentialValid(baseUrl)) { return Right(GetCredentialViewState(baseUrl, userName, password)); } else { - return Left(GetCredentialFailure(const BadCredentials())); + return Left(GetCredentialFailure(BadCredentials())); } } catch (exception) { return Left(GetCredentialFailure(exception)); diff --git a/lib/features/login/domain/usecases/get_stored_token_oidc_interactor.dart b/lib/features/login/domain/usecases/get_stored_token_oidc_interactor.dart index f82f3e237..f64361282 100644 --- a/lib/features/login/domain/usecases/get_stored_token_oidc_interactor.dart +++ b/lib/features/login/domain/usecases/get_stored_token_oidc_interactor.dart @@ -35,7 +35,7 @@ class GetStoredTokenOidcInteractor { if (_isCredentialValid(baseUrl)) { yield Right(GetStoredTokenOidcSuccess(baseUrl, tokenOidc, oidcConfiguration)); } else { - yield Left(GetStoredTokenOidcFailure(const InvalidBaseUrl())); + yield Left(GetStoredTokenOidcFailure(InvalidBaseUrl())); } } catch (e) { log('GetStoredTokenOidcInteractor::execute(): $e'); diff --git a/lib/features/session/data/datasource_impl/session_datasource_impl.dart b/lib/features/session/data/datasource_impl/session_datasource_impl.dart index 61f4ac1f1..f0ea39031 100644 --- a/lib/features/session/data/datasource_impl/session_datasource_impl.dart +++ b/lib/features/session/data/datasource_impl/session_datasource_impl.dart @@ -1,19 +1,34 @@ +import 'package:core/data/network/remote_exception_thrower.dart'; +import 'package:core/domain/exceptions/remote_exception.dart'; +import 'package:core/utils/app_logger.dart'; +import 'package:dio/dio.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; import 'package:tmail_ui_user/features/session/data/datasource/session_datasource.dart'; import 'package:tmail_ui_user/features/session/data/network/session_api.dart'; class SessionDataSourceImpl extends SessionDataSource { - final SessionAPI sessionAPI; + final SessionAPI _sessionAPI; + final RemoteExceptionThrower _remoteExceptionThrower; - SessionDataSourceImpl(this.sessionAPI); + SessionDataSourceImpl(this._sessionAPI, this._remoteExceptionThrower); @override Future getSession() { return Future.sync(() async { - return await sessionAPI.getSession(); + return await _sessionAPI.getSession(); }).catchError((error) { - throw error; + _remoteExceptionThrower.throwRemoteException(error, handler: (DioError error) { + if (error.response?.statusCode == 502) { + throw BadGateway(); + } else { + log('SessionDataSourceImpl::getSession(): statusMessage: ${error.response?.statusMessage}'); + throw UnknownError( + code: error.response?.statusCode, + message: error.response?.statusMessage); + } + }); }); } } \ No newline at end of file diff --git a/lib/features/session/presentation/session_controller.dart b/lib/features/session/presentation/session_controller.dart index c20085f54..a5bc68012 100644 --- a/lib/features/session/presentation/session_controller.dart +++ b/lib/features/session/presentation/session_controller.dart @@ -1,10 +1,15 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/utils/app_toast.dart'; +import 'package:core/domain/exceptions/remote_exception.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/authentication_exception.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/session/domain/state/get_session_state.dart'; import 'package:tmail_ui_user/features/session/domain/usecases/get_session_interactor.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -14,6 +19,7 @@ class SessionController extends GetxController { final CachingManager _cachingManager; final DeleteAuthorityOidcInteractor _deleteAuthorityOidcInteractor; final AuthorizationInterceptors _authorizationInterceptors; + final AppToast _appToast; SessionController( this._getSessionInteractor, @@ -21,7 +27,7 @@ class SessionController extends GetxController { this._cachingManager, this._deleteAuthorityOidcInteractor, this._authorizationInterceptors, - ); + this._appToast); @override void onReady() { @@ -32,8 +38,32 @@ class SessionController extends GetxController { void _getSession() async { await _getSessionInteractor.execute() .then((response) => response.fold( - (failure) => _goToLogin(), - (success) => success is GetSessionSuccess ? _goToMailboxDashBoard(success) : _goToLogin())); + (failure) { + _handleSessionFailure(failure); + _goToLogin(); + }, + (success) => success is GetSessionSuccess + ? _goToMailboxDashBoard(success) + : _goToLogin())); + } + + void _handleSessionFailure(Failure failure) { + if (failure is GetSessionFailure) { + final sessionException = failure.exception; + if (_checkUrlError(sessionException) && currentContext != null) { + _appToast.showErrorToast(AppLocalizations.of(currentContext!).wrongUrlMessage); + } else if (sessionException is UnknownError && currentContext != null) { + if (sessionException.message != null) { + _appToast.showErrorToast('[${sessionException.code}] ${sessionException.message}'); + } else { + _appToast.showErrorToast(AppLocalizations.of(currentContext!).unknown_error_login_message); + } + } + } + } + + bool _checkUrlError(dynamic sessionException) { + return sessionException is ConnectError || sessionException is BadGateway; } void _goToLogin() async { diff --git a/lib/features/session/presentation/session_page_bindings.dart b/lib/features/session/presentation/session_page_bindings.dart index b2b3083ed..a27cee64c 100644 --- a/lib/features/session/presentation/session_page_bindings.dart +++ b/lib/features/session/presentation/session_page_bindings.dart @@ -1,3 +1,4 @@ +import 'package:core/presentation/utils/app_toast.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; @@ -25,6 +26,7 @@ class SessionPageBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 9f3daea61..6cb693f96 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-06-13T12:33:59.446625", + "@@last_modified": "2022-06-22T11:25:25.867848", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -1417,5 +1417,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "wrongUrlMessage": "Server URL is not valid, please try again", + "@wrongUrlMessage": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/bindings/network/network_bindings.dart b/lib/main/bindings/network/network_bindings.dart index 1725cabe1..2fe421c06 100644 --- a/lib/main/bindings/network/network_bindings.dart +++ b/lib/main/bindings/network/network_bindings.dart @@ -26,6 +26,7 @@ class NetworkBindings extends Bindings { _bindingDio(); _bindingApi(); _bindingConnection(); + _bindingException(); } void _bindingBaseOption() { @@ -78,4 +79,8 @@ class NetworkBindings extends Bindings { void _bindingConnection() { Get.put(Connectivity()); } + + void _bindingException() { + Get.put(RemoteExceptionThrower()); + } } \ No newline at end of file diff --git a/lib/main/bindings/session/session_bindings.dart b/lib/main/bindings/session/session_bindings.dart index 2904a2e4a..7be85fde0 100644 --- a/lib/main/bindings/session/session_bindings.dart +++ b/lib/main/bindings/session/session_bindings.dart @@ -1,3 +1,4 @@ +import 'package:core/core.dart'; import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/base_bindings.dart'; import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; @@ -11,11 +12,6 @@ import 'package:tmail_ui_user/features/session/domain/usecases/get_session_inter class SessionBindings extends BaseBindings { - @override - void dependencies() { - super.dependencies(); - } - @override void bindingsController() { } @@ -27,7 +23,9 @@ class SessionBindings extends BaseBindings { @override void bindingsDataSourceImpl() { - Get.put(SessionDataSourceImpl(Get.find())); + Get.put(SessionDataSourceImpl( + Get.find(), + Get.find())); } @override diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3411e0211..7bc56c437 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -1448,4 +1448,9 @@ class AppLocalizations { name: 'noPreviewAvailable', ); } + + String get wrongUrlMessage { + return Intl.message('Server URL is not valid, please try again', + name: 'wrongUrlMessage'); + } } \ No newline at end of file