From b25b4dcf5c4d63d6ac82c18bf37bc292db6584d5 Mon Sep 17 00:00:00 2001 From: Dat PHAM HOANG Date: Mon, 12 Aug 2024 18:13:08 +0700 Subject: [PATCH] TF-2934 Handle other failed case of rename mailbox --- .../set_mailbox_name_exception.dart | 33 +++++++++ .../usecases/rename_mailbox_interactor.dart | 5 +- .../presentation/mailbox_controller.dart | 16 +++++ .../search_mailbox_controller.dart | 16 +++++ lib/l10n/intl_messages.arb | 8 ++- lib/main/localizations/app_localizations.dart | 10 ++- .../set_mailbox_name_exception_test.dart | 71 +++++++++++++++++++ 7 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 lib/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart create mode 100644 test/features/mailbox/domain/exceptions/set_mailbox_name_exception_test.dart diff --git a/lib/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart b/lib/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart new file mode 100644 index 000000000..3f379df31 --- /dev/null +++ b/lib/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart @@ -0,0 +1,33 @@ +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart'; + +class SetMailboxNameException implements Exception { + static const emptyMailboxNameDescription = 'has an empty part within its mailbox name'; + static const mailboxNameContainsInvalidCharactersDescription = 'contains one of the forbidden characters'; + + static SetMailboxNameException detectMailboxNameException(Object exception, MailboxId mailboxId) { + if (exception is SetMethodException) { + final setError = exception.mapErrors[mailboxId.id]; + if (setError == null) { + return SetMailboxNameException(); + } + + final errorDescription = setError.description; + if (errorDescription == null || errorDescription.isEmpty) { + return SetMailboxNameException(); + } + + if (errorDescription.contains(emptyMailboxNameDescription)) { + return EmptyMailboxNameException(); + } else if (errorDescription.contains(mailboxNameContainsInvalidCharactersDescription)) { + return ContainsInvalidCharactersMailboxNameException(); + } + return SetMailboxNameException(); + } + return SetMailboxNameException(); + } +} + +class EmptyMailboxNameException implements SetMailboxNameException {} + +class ContainsInvalidCharactersMailboxNameException implements SetMailboxNameException {} diff --git a/lib/features/mailbox/domain/usecases/rename_mailbox_interactor.dart b/lib/features/mailbox/domain/usecases/rename_mailbox_interactor.dart index 26a989448..893967ec3 100644 --- a/lib/features/mailbox/domain/usecases/rename_mailbox_interactor.dart +++ b/lib/features/mailbox/domain/usecases/rename_mailbox_interactor.dart @@ -2,6 +2,7 @@ import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/rename_mailbox_state.dart'; @@ -24,7 +25,9 @@ class RenameMailboxInteractor { yield Left(RenameMailboxFailure(null)); } } catch (e) { - yield Left(RenameMailboxFailure(e)); + logError('RenameMailboxInteractor::execute(): error: $e'); + final exception = SetMailboxNameException.detectMailboxNameException(e, request.mailboxId); + yield Left(RenameMailboxFailure(exception)); } } } \ No newline at end of file diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index f65fe3918..21192e457 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -29,6 +29,7 @@ import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_sta import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox/domain/constants/mailbox_constants.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_action_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_state.dart'; @@ -192,6 +193,8 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM super.handleFailureViewState(failure); if (failure is CreateNewMailboxFailure) { _createNewMailboxFailure(failure); + } else if (failure is RenameMailboxFailure) { + _renameMailboxFailure(failure); } else if (failure is DeleteMultipleMailboxFailure) { _deleteMailboxFailure(failure); } else if (failure is RefreshChangesAllMailboxFailure) { @@ -632,6 +635,19 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM } } + void _renameMailboxFailure(RenameMailboxFailure failure) { + if (currentOverlayContext != null && currentContext != null) { + final exception = failure.exception; + var messageError = AppLocalizations.of(currentContext!).renameFolderFailure; + if (exception is EmptyMailboxNameException) { + messageError = AppLocalizations.of(currentContext!).nameOfFolderIsRequired; + } else if (exception is ContainsInvalidCharactersMailboxNameException) { + messageError = AppLocalizations.of(currentContext!).folderNameCannotContainSpecialCharacters; + } + appToast.showToastErrorMessage(currentOverlayContext!, messageError); + } + } + void openSearchViewAction(BuildContext context) { if (PlatformInfo.isWeb) { SearchMailboxBindings().dependencies(); diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index 83a0fe9d8..917658366 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -22,6 +22,7 @@ import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/mailbox_action_handler_mixin.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; import 'package:tmail_ui_user/features/mailbox/domain/constants/mailbox_constants.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_action_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_state.dart'; @@ -120,6 +121,8 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa _handleSearchMailboxFailure(failure); } else if (failure is CreateNewMailboxFailure) { _createNewMailboxFailure(failure); + } else if (failure is RenameMailboxFailure) { + _renameMailboxFailure(failure); } } @@ -708,6 +711,19 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa } } + void _renameMailboxFailure(RenameMailboxFailure failure) { + if (currentOverlayContext != null && currentContext != null) { + final exception = failure.exception; + var messageError = AppLocalizations.of(currentContext!).renameFolderFailure; + if (exception is EmptyMailboxNameException) { + messageError = AppLocalizations.of(currentContext!).nameOfFolderIsRequired; + } else if (exception is ContainsInvalidCharactersMailboxNameException) { + messageError = AppLocalizations.of(currentContext!).folderNameCannotContainSpecialCharacters; + } + appToast.showToastErrorMessage(currentOverlayContext!, messageError); + } + } + void clearAllTextInputSearchForm() { textInputSearchController.clear(); currentSearchQuery.value = ''; diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index ddb80ff94..c76085944 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2024-08-05T16:49:32.139855", + "@@last_modified": "2024-08-12T18:11:14.971152", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -704,6 +704,12 @@ "placeholders_order": [], "placeholders": {} }, + "renameFolderFailure": "Rename folder failure", + "@renameFolderFailure": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, "this_field_cannot_be_blank": "This field cannot be blank", "@this_field_cannot_be_blank": { "type": "text", diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 0538c1253..0167e7783 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -718,8 +718,14 @@ class AppLocalizations { String get renameFolder { return Intl.message( - 'Rename folder', - name: 'renameFolder'); + 'Rename folder', + name: 'renameFolder'); + } + + String get renameFolderFailure { + return Intl.message( + 'Rename folder failure', + name: 'renameFolderFailure'); } String get this_field_cannot_be_blank { diff --git a/test/features/mailbox/domain/exceptions/set_mailbox_name_exception_test.dart b/test/features/mailbox/domain/exceptions/set_mailbox_name_exception_test.dart new file mode 100644 index 000000000..5a782874a --- /dev/null +++ b/test/features/mailbox/domain/exceptions/set_mailbox_name_exception_test.dart @@ -0,0 +1,71 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_name_exception.dart'; + +void main() { + group('SetMailboxNameException', () { + final mailboxId = MailboxId(Id('mailboxId')); + + test('should return SetMailboxNameException when exception is not SetMethodException', () { + final exception = Exception('Some other exception'); + + final result = SetMailboxNameException.detectMailboxNameException(exception, mailboxId); + expect(result, isA()); + }); + + test('should return SetMailboxNameException when error is SetMailboxException without details', () { + final setMethodException = SetMethodException({}); + + final result = SetMailboxNameException.detectMailboxNameException(setMethodException, mailboxId); + expect(result, isA()); + }); + + test('should return SetMailboxException when errorDescription is null', () { + final setMethodException = SetMethodException({ + mailboxId.id: SetError(SetError.invalidArguments, description: null) + }); + + final result = SetMailboxNameException.detectMailboxNameException(setMethodException, mailboxId); + expect(result, isA()); + }); + + test('should return SetMailboxException when errorDescription is empty', () { + final setMethodException = SetMethodException({ + mailboxId.id: SetError(SetError.invalidArguments, description: '') + }); + + final result = SetMailboxNameException.detectMailboxNameException(setMethodException, mailboxId); + expect(result, isA()); + }); + + test('should return EmptyMailboxNameException when errorDescription contains emptyMailboxNameDescription', () { + final setMethodException = SetMethodException({ + mailboxId.id: SetError(SetError.invalidArguments, description: ' \' has an empty part within its mailbox name considering as a delimiter') + }); + + final result = SetMailboxNameException.detectMailboxNameException(setMethodException, mailboxId); + expect(result, isA()); + }); + + test('should return ContainsInvalidCharactersMailboxNameException when errorDescription contains mailboxNameContainsInvalidCharactersDescription', () { + final setMethodException = SetMethodException({ + mailboxId.id: SetError(SetError.invalidArguments, description: '#hello contains one of the forbidden characters or starts with #') + }); + + final result = SetMailboxNameException.detectMailboxNameException(setMethodException, mailboxId); + expect(result, isA()); + }); + + test('should return SetMailboxNameException when errorDescription does not contain specific descriptions', () { + final setMethodException = SetMethodException({ + mailboxId.id: SetError(SetError.invalidArguments, description: 'Some other description') + }); + + final result = SetMailboxNameException.detectMailboxNameException(setMethodException, mailboxId); + expect(result, isA()); + }); + }); +} \ No newline at end of file