From 6720709a2e3d8c5873e8670f9f76253198d97484 Mon Sep 17 00:00:00 2001 From: Florent Azavant Date: Fri, 24 Jan 2025 11:49:38 +0100 Subject: [PATCH] TF-2305 `Session::getOwnEmailAddress` method to fetch the user email address from `urn:ietf:params:jmap:principals imip mailto` property if not present in the session username, which is the case for Cyrus --- lib/features/base/base_controller.dart | 2 +- lib/features/base/mixin/logout_mixin.dart | 4 +- .../presentation/composer_controller.dart | 8 +- .../create_email_request_extension.dart | 8 +- .../controller/single_email_controller.dart | 6 +- .../domain/extensions/session_extensions.dart | 9 +- .../identity_creator_controller.dart | 4 +- .../mailbox/presentation/mailbox_view.dart | 3 +- .../presentation/mailbox_view_web.dart | 3 +- .../mailbox_dashboard_controller.dart | 4 +- .../controller/search_controller.dart | 16 +-- .../mailbox_dashboard_view_web.dart | 6 +- .../mixin/user_setting_popup_menu_mixin.dart | 7 +- .../model/search/quick_search_filter.dart | 6 +- .../search_filters/search_filter_button.dart | 4 - .../widgets/search_input_form_widget.dart | 5 +- .../manage_account_dashboard_controller.dart | 2 +- .../settings/settings_first_level_view.dart | 4 +- .../email/presentation/search_email_view.dart | 5 +- .../unknown_address_exception.dart | 1 + model/lib/extensions/session_extension.dart | 37 ++++++ .../lib/principals/capability_principals.dart | 3 + .../extensions/session_extension_test.dart | 123 +++++++++++++++++- 23 files changed, 212 insertions(+), 58 deletions(-) create mode 100644 model/lib/error_type_handler/unknown_address_exception.dart create mode 100644 model/lib/principals/capability_principals.dart diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart index 2a7998c22..9cf847d3b 100644 --- a/lib/features/base/base_controller.dart +++ b/lib/features/base/base_controller.dart @@ -451,7 +451,7 @@ abstract class BaseController extends GetxController if (PlatformInfo.isMobile) { showLogoutConfirmDialog( context: context, - username: session?.username.value ?? '', + userAddress: session?.getOwnEmailAddress() ?? '', onConfirmAction: () => _handleLogoutAction(session, accountId), ); } else { diff --git a/lib/features/base/mixin/logout_mixin.dart b/lib/features/base/mixin/logout_mixin.dart index 24b55faf3..30ba4aaef 100644 --- a/lib/features/base/mixin/logout_mixin.dart +++ b/lib/features/base/mixin/logout_mixin.dart @@ -6,7 +6,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; mixin LogoutMixin implements MessageDialogActionMixin { void showLogoutConfirmDialog({ required BuildContext context, - required String username, + required String userAddress, required Function? onConfirmAction, }) { final appLocalizations = AppLocalizations.of(context); @@ -33,7 +33,7 @@ mixin LogoutMixin implements MessageDialogActionMixin { listTextSpan: [ TextSpan(text: AppLocalizations.of(context).messageConfirmationLogout), TextSpan( - text: ' $username', + text: ' $userAddress', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: AppColor.colorTextBody, fontSize: 15, diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 2cf14ef59..8ce97eab0 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -832,15 +832,15 @@ class ComposerController extends BaseController required EmailActionType actionType, String? listPost, }) { - final userName = mailboxDashBoardController.sessionCurrent?.username.value; + final senderEmailAddress = mailboxDashBoardController.sessionCurrent?.getOwnEmailAddress(); final isSender = presentationEmail.from .asList() - .any((element) => element.emailAddress.isNotEmpty && element.emailAddress == userName); + .any((element) => element.emailAddress.isNotEmpty && element.emailAddress == senderEmailAddress); final recipients = presentationEmail.generateRecipientsEmailAddressForComposer( emailActionType: actionType, isSender: isSender, - userName: userName, + userName: senderEmailAddress, listPost: listPost, ); @@ -1506,7 +1506,7 @@ class ComposerController extends BaseController if (arguments.emailActionType == EmailActionType.editDraft) { return arguments.presentationEmail?.firstEmailAddressInFrom ?? ''; } else { - return mailboxDashBoardController.sessionCurrent?.username.value ?? ''; + return mailboxDashBoardController.sessionCurrent?.getOwnEmailAddress() ?? ''; } } return ''; diff --git a/lib/features/composer/presentation/extensions/create_email_request_extension.dart b/lib/features/composer/presentation/extensions/create_email_request_extension.dart index e2dda9257..25ad3abb1 100644 --- a/lib/features/composer/presentation/extensions/create_email_request_extension.dart +++ b/lib/features/composer/presentation/extensions/create_email_request_extension.dart @@ -9,7 +9,7 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/extensions/email_address_extension.dart'; -import 'package:model/extensions/username_extension.dart'; +import 'package:model/extensions/session_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/identity_extension.dart'; @@ -26,7 +26,7 @@ extension CreateEmailRequestExtension on CreateEmailRequest { if (identity?.email?.isNotEmpty == true) { return { identity!.toEmailAddress() }; } else { - return { session.username.toEmailAddress() }; + return { EmailAddress(null, session.getOwnEmailAddress()) }; } } @@ -34,7 +34,7 @@ extension CreateEmailRequestExtension on CreateEmailRequest { if (emailActionType == EmailActionType.editDraft && fromSender.isNotEmpty) { return fromSender.first.emailAddress; } else { - return session.username.value; + return session.getOwnEmailAddress(); } } @@ -42,7 +42,7 @@ extension CreateEmailRequestExtension on CreateEmailRequest { if (identity?.replyTo?.isNotEmpty == true) { return identity!.replyTo!.toSet(); } else { - return { session.username.toEmailAddress() }; + return { EmailAddress(null, session.getOwnEmailAddress()) }; } } diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 524b4b65d..e391b7bf1 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -1370,7 +1370,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { return; } - final receiverEmailAddress = _getReceiverEmailAddress(currentEmail!) ?? session!.username.value; + final receiverEmailAddress = _getReceiverEmailAddress(currentEmail!) ?? session!.getOwnEmailAddress(); log('SingleEmailController::_handleSendReceiptToSenderAction():receiverEmailAddress: $receiverEmailAddress'); final mdnToSender = _generateMDN(context, currentEmail!, receiverEmailAddress); final sendReceiptRequest = SendReceiptToSenderRequest( @@ -2243,8 +2243,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { listEmailAddressAttendees.addAll(listEmailAddress); - final username = mailboxDashBoardController.sessionCurrent?.username.value ?? ''; - final listEmailAddressMailTo = listEmailAddressAttendees.removeInvalidEmails(username); + final currentUserEmail = mailboxDashBoardController.sessionCurrent?.getOwnEmailAddress() ?? ''; + final listEmailAddressMailTo = listEmailAddressAttendees.removeInvalidEmails(currentUserEmail); log('SingleEmailController::handleMailToAttendees: listEmailAddressMailTo = $listEmailAddressMailTo'); mailboxDashBoardController.goToComposer( ComposerArguments.fromMailtoUri(listEmailAddress: listEmailAddressMailTo) diff --git a/lib/features/home/domain/extensions/session_extensions.dart b/lib/features/home/domain/extensions/session_extensions.dart index 5571747bc..274132899 100644 --- a/lib/features/home/domain/extensions/session_extensions.dart +++ b/lib/features/home/domain/extensions/session_extensions.dart @@ -5,7 +5,6 @@ import 'package:contact/contact/model/autocomplete_capability.dart'; import 'package:contact/contact/model/capability_contact.dart'; import 'package:core/presentation/extensions/uri_extension.dart'; import 'package:core/utils/app_logger.dart'; -import 'package:get/get.dart'; import 'package:jmap_dart_client/http/converter/state_converter.dart'; import 'package:jmap_dart_client/http/converter/user_name_converter.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; @@ -61,13 +60,7 @@ extension SessionExtensions on Session { String get internalDomain { try { - if (GetUtils.isEmail(username.value)) { - return username.value.split('@').last; - } else if (GetUtils.isEmail(personalAccount.name.value)) { - return personalAccount.name.value.split('@').last; - } else { - return ''; - } + return getOwnEmailAddress().split('@').last; } catch (e) { logError('SessionExtensions::internalDomain: Exception: $e'); return ''; diff --git a/lib/features/identity_creator/presentation/identity_creator_controller.dart b/lib/features/identity_creator/presentation/identity_creator_controller.dart index 466278236..aa5e14064 100644 --- a/lib/features/identity_creator/presentation/identity_creator_controller.dart +++ b/lib/features/identity_creator/presentation/identity_creator_controller.dart @@ -375,8 +375,8 @@ class IdentityCreatorController extends BaseController with DragDropFileMixin im void _setDefaultEmailAddressList() { listEmailAddressOfReplyTo.add(noneEmailAddress); - if (session?.username.value.isNotEmpty == true) { - final userEmailAddress = EmailAddress(null, session?.username.value); + if (session?.getOwnEmailAddress() != null) { + final userEmailAddress = EmailAddress(null, session?.getOwnEmailAddress()); listEmailAddressDefault.add(userEmailAddress); listEmailAddressOfReplyTo.addAll(listEmailAddressDefault); } diff --git a/lib/features/mailbox/presentation/mailbox_view.dart b/lib/features/mailbox/presentation/mailbox_view.dart index cca76b273..3eb09b7a3 100644 --- a/lib/features/mailbox/presentation/mailbox_view.dart +++ b/lib/features/mailbox/presentation/mailbox_view.dart @@ -3,6 +3,7 @@ import 'package:core/utils/direction_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/widget/application_version_widget.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/base_mailbox_view.dart'; @@ -224,7 +225,7 @@ class MailboxView extends BaseMailboxView { } return UserInformationWidget( userName: controller.mailboxDashBoardController.accountId.value != null - ? controller.mailboxDashBoardController.sessionCurrent?.username + ? UserName(controller.mailboxDashBoardController.sessionCurrent!.getOwnEmailAddress()) : null, subtitle: AppLocalizations.of(context).manage_account, onSubtitleClick: controller.mailboxDashBoardController.goToSettings, diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart index d29576fb2..84ccd0ae5 100644 --- a/lib/features/mailbox/presentation/mailbox_view_web.dart +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -2,6 +2,7 @@ import 'package:core/core.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/model.dart'; import 'package:tmail_ui_user/features/base/widget/application_logo_with_text_widget.dart'; import 'package:tmail_ui_user/features/base/widget/application_version_widget.dart'; @@ -141,7 +142,7 @@ class MailboxView extends BaseMailboxView { if (!controller.responsiveUtils.isDesktop(context)) Obx(() => UserInformationWidget( userName: controller.mailboxDashBoardController.accountId.value != null - ? controller.mailboxDashBoardController.sessionCurrent?.username + ? UserName(controller.mailboxDashBoardController.sessionCurrent!.getOwnEmailAddress()) : null, subtitle: AppLocalizations.of(context).manage_account, onSubtitleClick: controller.mailboxDashBoardController.goToSettings, diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 684fd8bb7..5fdc04e8a 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -3125,7 +3125,7 @@ class MailboxDashBoardController extends ReloadableController isRecoveringDeletedMessage.value = true; } - String get userEmail => sessionCurrent?.username.value ?? ''; + String get userEmail => sessionCurrent?.getOwnEmailAddress() ?? ''; Future _removeComposerCacheOnWeb() async { await _removeComposerCacheOnWebInteractor.execute(); @@ -3162,7 +3162,7 @@ class MailboxDashBoardController extends ReloadableController position, popupMenuUserSettingActionTile( context, - sessionCurrent?.username, + sessionCurrent?.getOwnEmailAddress(), onLogoutAction: () { popBack(); logout( diff --git a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart index accfd2b12..5a7b2afa6 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart @@ -9,7 +9,6 @@ import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; -import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator_property.dart'; @@ -17,6 +16,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:model/email/presentation_email.dart'; import 'package:model/extensions/email_filter_condition_extension.dart'; +import 'package:model/extensions/session_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/date_range_picker_mixin.dart'; @@ -98,7 +98,7 @@ class SearchController extends BaseController with DateRangePickerMixin { sort: {}..add( EmailComparator(EmailComparatorProperty.receivedAt) ..setIsAscending(false)), - filter: _mappingToFilterOnSuggestionForm(userName: session.username, query: query), + filter: _mappingToFilterOnSuggestionForm(currentUserEmail: session.getOwnEmailAddress(), query: query), properties: EmailUtils.getPropertiesForEmailGetMethod(session, accountId), ).then((result) => result.fold( (failure) => [], @@ -108,7 +108,7 @@ class SearchController extends BaseController with DateRangePickerMixin { )); } - Filter? _mappingToFilterOnSuggestionForm({required String query, required UserName userName}) { + Filter? _mappingToFilterOnSuggestionForm({required String query, required String currentUserEmail}) { log('SearchController::_mappingToFilterOnSuggestionForm():query: $query'); final filterCondition = EmailFilterCondition( text: query.isNotEmpty == true ? query : null, @@ -122,7 +122,7 @@ class SearchController extends BaseController with DateRangePickerMixin { ? true : null, from: listFilterOnSuggestionForm.contains(QuickSearchFilter.fromMe) - ? userName.value + ? currentUserEmail : null, hasKeyword: listFilterOnSuggestionForm.contains(QuickSearchFilter.starred) ? KeyWordIdentifier.emailFlagged.value @@ -134,7 +134,7 @@ class SearchController extends BaseController with DateRangePickerMixin { : null; } - void applyFilterSuggestionToSearchFilter(UserName? userName) { + void applyFilterSuggestionToSearchFilter(String? currentUserEmail) { final receiveTime = listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days) ? EmailReceiveTimeType.last7Days : EmailReceiveTimeType.allTime; @@ -142,11 +142,11 @@ class SearchController extends BaseController with DateRangePickerMixin { final hasAttachment = listFilterOnSuggestionForm.contains(QuickSearchFilter.hasAttachment) ? true : false; var listFromAddress = searchEmailFilter.value.from; - if (userName != null) { + if (currentUserEmail != null) { if (listFilterOnSuggestionForm.contains(QuickSearchFilter.fromMe)) { - listFromAddress.add(userName.value); + listFromAddress.add(currentUserEmail); } else { - listFromAddress.remove(userName.value); + listFromAddress.remove(currentUserEmail); } } diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index 6d2016723..74a1f5e8d 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -5,6 +5,7 @@ import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart'; +import 'package:model/extensions/session_extension.dart'; import 'package:model/extensions/username_extension.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart'; import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart'; @@ -540,7 +541,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { final searchEmailFilter = controller.searchController.searchEmailFilter.value; final sortOrderType = controller.searchController.sortOrderFiltered; final listAddressOfFrom = controller.searchController.listAddressOfFromFiltered; - final userName = controller.sessionCurrent?.username; + final currentUserEmail = controller.sessionCurrent?.getOwnEmailAddress(); final startDate = controller.searchController.startDateFiltered; final endDate = controller.searchController.endDateFiltered; final receiveTimeType = controller.searchController.receiveTimeFiltered; @@ -551,7 +552,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { context, searchEmailFilter, sortOrderType, - userName); + currentUserEmail); EdgeInsetsGeometry? buttonPadding; if (searchFilter != QuickSearchFilter.sortBy) { @@ -570,7 +571,6 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { sortOrderType: sortOrderType, listAddressOfFrom: listAddressOfFrom, listAddressOfTo: listAddressOfTo, - userName: userName, mailbox: mailbox, buttonPadding: buttonPadding, onSelectSearchFilterAction: _onSelectSearchFilterAction, diff --git a/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart b/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart index 08b5592cd..3cb76da20 100644 --- a/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart +++ b/lib/features/mailbox_dashboard/presentation/mixin/user_setting_popup_menu_mixin.dart @@ -4,7 +4,6 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/views/popup_menu/popup_menu_item_widget.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; mixin UserSettingPopupMenuMixin { @@ -12,14 +11,14 @@ mixin UserSettingPopupMenuMixin { List popupMenuUserSettingActionTile( BuildContext context, - UserName? userName, + String? currentUserEmail, { Function? onLogoutAction, Function? onSettingAction } ) { return [ - if (userName != null) + if(currentUserEmail != null) PopupMenuItem( enabled: false, padding: EdgeInsets.zero, @@ -28,7 +27,7 @@ mixin UserSettingPopupMenuMixin { child: ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20), title: SelectableText( - userName.value, + currentUserEmail, maxLines: 1, style: const TextStyle( fontSize: 15, diff --git a/lib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart b/lib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart index 9c33a2b47..dd5b1bec2 100644 --- a/lib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart +++ b/lib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart @@ -126,7 +126,7 @@ enum QuickSearchFilter { BuildContext context, SearchEmailFilter searchFilter, EmailSortOrderType sortOrderType, - UserName? userName, + String? currentUserEmail, ) { switch (this) { case QuickSearchFilter.hasAttachment: @@ -135,8 +135,8 @@ enum QuickSearchFilter { return searchFilter.emailReceiveTimeType == EmailReceiveTimeType.last7Days; case QuickSearchFilter.fromMe: return searchFilter.from.length == 1 && - userName?.value.isNotEmpty == true && - userName?.value == searchFilter.from.first; + currentUserEmail?.isNotEmpty == true && + currentUserEmail == searchFilter.from.first; case QuickSearchFilter.sortBy: return sortOrderType != EmailSortOrderType.mostRecent; case QuickSearchFilter.dateTime: diff --git a/lib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart b/lib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart index 792b478ea..cdb693224 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart @@ -4,7 +4,6 @@ import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; @@ -31,7 +30,6 @@ class SearchFilterButton extends StatelessWidget { final DateTime? endDate; final Set? listAddressOfFrom; final Set? listAddressOfTo; - final UserName? userName; final PresentationMailbox? mailbox; final Color? backgroundColor; final EdgeInsetsGeometry? buttonPadding; @@ -50,7 +48,6 @@ class SearchFilterButton extends StatelessWidget { this.endDate, this.listAddressOfFrom, this.listAddressOfTo, - this.userName, this.mailbox, this.backgroundColor, this.buttonPadding, @@ -67,7 +64,6 @@ class SearchFilterButton extends StatelessWidget { endDate: startDate, sortOrderType: sortOrderType, listAddressOfFrom: listAddressOfFrom, - userName: userName, mailbox: mailbox, listAddressOfTo: listAddressOfTo, ); diff --git a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart index 6d9869f32..f7ea4651a 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart @@ -15,6 +15,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/email/presentation_email.dart'; +import 'package:model/extensions/session_extension.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart'; @@ -146,7 +147,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { if (queryString.isNotEmpty || _searchController.listFilterOnSuggestionForm.isNotEmpty) { _searchController.clearSearchFilter(); - _searchController.applyFilterSuggestionToSearchFilter(_dashBoardController.sessionCurrent?.username); + _searchController.applyFilterSuggestionToSearchFilter(_dashBoardController.sessionCurrent?.getOwnEmailAddress()); _dashBoardController.searchEmailByQueryString(queryString); } else { _dashBoardController.clearSearchEmail(); @@ -166,7 +167,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { _searchController.searchFocus.unfocus(); _searchController.enableSearch(); _searchController.clearSearchFilter(); - _searchController.applyFilterSuggestionToSearchFilter(_dashBoardController.sessionCurrent?.username); + _searchController.applyFilterSuggestionToSearchFilter(_dashBoardController.sessionCurrent?.getOwnEmailAddress()); _dashBoardController.searchEmailByQueryString(recent.value); } diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart index 15cad8151..4e74c2089 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart @@ -363,7 +363,7 @@ class ManageAccountDashBoardController extends ReloadableController with UserSet position, popupMenuUserSettingActionTile( context, - sessionCurrent?.username, + sessionCurrent?.getOwnEmailAddress(), onLogoutAction: () { popBack(); logout(context, sessionCurrent, accountId.value); diff --git a/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart b/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart index ea1f7948c..2af88b465 100644 --- a/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart +++ b/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart @@ -2,6 +2,8 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:model/extensions/session_extension.dart'; import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/widgets/user_information_widget.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings/settings_controller.dart'; @@ -20,7 +22,7 @@ class SettingsFirstLevelView extends GetWidget { child: Column(children: [ Obx(() => UserInformationWidget( userName: controller.manageAccountDashboardController.accountId.value != null - ? controller.manageAccountDashboardController.sessionCurrent?.username + ? UserName(controller.manageAccountDashboardController.sessionCurrent!.getOwnEmailAddress()) : null, padding: SettingsUtils.getPaddingInFirstLevel(context, controller.responsiveUtils), titlePadding: const EdgeInsetsDirectional.only(start: 16))), diff --git a/lib/features/search/email/presentation/search_email_view.dart b/lib/features/search/email/presentation/search_email_view.dart index 2e95dbe37..d422074e9 100644 --- a/lib/features/search/email/presentation/search_email_view.dart +++ b/lib/features/search/email/presentation/search_email_view.dart @@ -250,7 +250,7 @@ class SearchEmailView extends GetWidget final searchEmailFilter = controller.searchEmailFilter.value; final sortOrderType = controller.emailSortOrderType.value; final listAddressOfFrom = controller.listAddressOfFromFiltered; - final userName = controller.session?.username; + final currentUserEmail = controller.session?.getOwnEmailAddress(); final startDate = controller.startDateFiltered; final endDate = controller.endDateFiltered; final receiveTimeType = controller.receiveTimeFiltered; @@ -261,7 +261,7 @@ class SearchEmailView extends GetWidget context, searchEmailFilter, sortOrderType, - userName); + currentUserEmail); return SearchFilterButton( key: Key('mobile_${searchFilter.name}_search_filter_button'), @@ -275,7 +275,6 @@ class SearchEmailView extends GetWidget sortOrderType: sortOrderType, listAddressOfFrom: listAddressOfFrom, listAddressOfTo: listAddressOfTo, - userName: userName, mailbox: mailbox, backgroundColor: searchFilter.getMobileBackgroundColor(isSelected: isSelected), onSelectSearchFilterAction: _onSelectSearchFilterAction, diff --git a/model/lib/error_type_handler/unknown_address_exception.dart b/model/lib/error_type_handler/unknown_address_exception.dart new file mode 100644 index 000000000..d6907c7ac --- /dev/null +++ b/model/lib/error_type_handler/unknown_address_exception.dart @@ -0,0 +1 @@ +class UnknownAddressException implements Exception {} diff --git a/model/lib/extensions/session_extension.dart b/model/lib/extensions/session_extension.dart index b5a386109..5fb3fb342 100644 --- a/model/lib/extensions/session_extension.dart +++ b/model/lib/extensions/session_extension.dart @@ -2,15 +2,20 @@ import 'dart:ui'; import 'package:core/presentation/extensions/uri_extension.dart'; +import 'package:get/get_utils/src/extensions/string_extensions.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/calendar_event_capability.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_properties.dart'; +import 'package:jmap_dart_client/jmap/core/capability/default_capability.dart'; import 'package:jmap_dart_client/jmap/core/capability/empty_capability.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:model/error_type_handler/account_exception.dart'; +import 'package:model/error_type_handler/unknown_address_exception.dart'; import 'package:model/error_type_handler/unknown_uri_exception.dart'; import 'package:model/model.dart'; +import 'package:model/principals/capability_principals.dart'; import 'package:uri/uri.dart'; extension SessionExtension on Session { @@ -66,6 +71,38 @@ extension SessionExtension on Session { } } + String getOwnEmailAddress() { + return username.value.isEmail ? username.value + : _getOwnEmailAddressFromPersonalAccount() + ?? _getOwnEmailAddressFromPrincipalsCapability() + ?? (throw UnknownAddressException()); + } + + String? _getOwnEmailAddressFromPersonalAccount() { + try { + return personalAccount.name.value.isEmail ? personalAccount.name.value : null; + } catch (_) { + return null; + } + } + + String? _getOwnEmailAddressFromPrincipalsCapability() { + try { + var principalsCapability = getCapabilityProperties(AccountId(Id(username.value)), capabilityPrincipals); + final sendTo = principalsCapability?.properties?['urn:ietf:params:jmap:calendars']?['sendTo']; + if (sendTo is Map) { + final wrappedAddress = sendTo['imip']; + if (wrappedAddress is String && wrappedAddress.startsWith('mailto:')) { + String address = wrappedAddress.substring("mailto:".length); + return address.isEmail ? address : null; + } + } + } catch (_) { + return null; + } + return null; + } + JmapAccount get personalAccount { if (accounts.isNotEmpty) { final listPersonalAccount = accounts.entries diff --git a/model/lib/principals/capability_principals.dart b/model/lib/principals/capability_principals.dart new file mode 100644 index 000000000..7a25e1287 --- /dev/null +++ b/model/lib/principals/capability_principals.dart @@ -0,0 +1,3 @@ +import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; + +final capabilityPrincipals = CapabilityIdentifier(Uri.parse('urn:ietf:params:jmap:principals')); diff --git a/model/test/extensions/session_extension_test.dart b/model/test/extensions/session_extension_test.dart index 8ba186a4a..9d05c7a89 100644 --- a/model/test/extensions/session_extension_test.dart +++ b/model/test/extensions/session_extension_test.dart @@ -5,12 +5,15 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/account/account.dart'; import 'package:jmap_dart_client/jmap/core/capability/calendar_event_capability.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; +import 'package:jmap_dart_client/jmap/core/capability/default_capability.dart'; import 'package:jmap_dart_client/jmap/core/capability/empty_capability.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:model/error_type_handler/unknown_address_exception.dart'; import 'package:model/extensions/session_extension.dart'; +import 'package:model/principals/capability_principals.dart'; void main() { final accountId = AccountId(Id('123abc')); @@ -80,7 +83,7 @@ void main() { test( 'should return null ' - 'when calendar event capability supportes no language', + 'when calendar event capability supports no language', () { // arrange final calendarEventCapability = CalendarEventCapability(); @@ -165,4 +168,122 @@ void main() { expect(calendarEventLanguage, 'vi'); }); }); + + group('getOwnEmailAddress test:', () { + test( + 'should return username.value ' + 'when it is a valid email and principals capability is absent', + () { + // arrange + final session = Session({}, {}, {}, UserName('test@example.com'), Uri(), Uri(), Uri(), Uri(), State(''),); + + // act + final emailAddress = session.getOwnEmailAddress(); + + // assert + expect(emailAddress, 'test@example.com'); + }); + + test( + 'should return username.value' + 'when it is a valid email and principals capability is present but has no address', + () { + // arrange + final session = Session( + {capabilityPrincipals: DefaultCapability({})}, + {}, {}, UserName('test@example.com'), Uri(), Uri(), Uri(), Uri(), State(''), + ); + + // act + final emailAddress = session.getOwnEmailAddress(); + + // assert + expect(emailAddress, 'test@example.com'); + }); + + test( + 'should return username.value' + 'when it is a valid email and principals capability is present with an address', + () { + // arrange + final session = Session( + {capabilityPrincipals: DefaultCapability({'key': {'subKey': 'mailto:another@example.com'}})}, + {}, {}, UserName('test@example.com'), Uri(), Uri(), Uri(), Uri(), State(''), + ); + + // act + final emailAddress = session.getOwnEmailAddress(); + + // assert + expect(emailAddress, 'test@example.com'); + }); + + test( + 'should throw exception' + 'when username is not a valid email and principals capability is absent', + () { + // arrange + final session = Session({}, {}, {}, UserName('notAnEmail'), Uri(), Uri(), Uri(), Uri(), State('')); + + // assert + expect(() => session.getOwnEmailAddress(), throwsA(isA())); + }); + + test( + 'should return null' + 'when username is not a valid email and principals capability is present but has no address', + () { + // arrange + final session = Session( + {capabilityPrincipals: DefaultCapability({})}, + {}, {}, UserName('notAnEmail'), Uri(), Uri(), Uri(), Uri(), State(''), + ); + + // assert + expect(() => session.getOwnEmailAddress(), throwsA(isA())); + }); + + test( + 'should return null' + 'when username is not a valid email and principals capability is present but has no valid address', + () { + // arrange + final session = Session( + {capabilityPrincipals: DefaultCapability({'key': {'subKey': 'test@example.com'}})}, + {}, {}, UserName('notAnEmail'), Uri(), Uri(), Uri(), Uri(), State(''), + ); + + // assert + expect(() => session.getOwnEmailAddress(), throwsA(isA())); + }); + + test( + 'should return email address from principals capability' + 'when username is not a valid email and principals capability is present with an address', + () { + // arrange + final capability = DefaultCapability({ + "currentUserPrincipalId": "bob", + "urn:ietf:params:jmap:calendars": { + "accountId": "bob", + "account": null, + "mayGetAvailability": true, + "sendTo": { + "imip": "mailto:bob@example.com" + } + } + }); + + final session = Session( + {capabilityPrincipals: capability}, + {}, {}, UserName('notAnEmail'), Uri(), Uri(), Uri(), Uri(), State(''), + ); + + // act + final emailAddress = session.getOwnEmailAddress(); + + // assert + expect(emailAddress, 'bob@example.com'); + }); + }); } \ No newline at end of file