From fea63725988c949d06b04eec46024b46d864e3fb Mon Sep 17 00:00:00 2001 From: dab246 Date: Sat, 23 Nov 2024 03:52:01 +0700 Subject: [PATCH] TF-3294 Fix BLUE-BAR mail to attendees duplicated recipients --- .../controller/single_email_controller.dart | 19 ++--- .../calendar_attendee_extension.dart | 12 ++++ .../calendar_organizer_extension.dart | 12 ++++ .../list_email_address_extension.dart | 9 +++ .../list_email_address_extension_test.dart | 71 +++++++++++++++++++ 5 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 lib/features/email/presentation/extensions/calendar_attendee_extension.dart create mode 100644 lib/features/email/presentation/extensions/calendar_organizer_extension.dart create mode 100644 model/test/extensions/list_email_address_extension_test.dart diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index e40e78fca3..928c8e2dfe 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -77,6 +77,8 @@ import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action import 'package:tmail_ui_user/features/email/presentation/bindings/calendar_event_interactor_bindings.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/email_supervisor_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/attachment_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_attendee_extension.dart'; +import 'package:tmail_ui_user/features/email/presentation/extensions/calendar_organizer_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/model/blob_calendar_event.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart'; @@ -1853,19 +1855,20 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void handleMailToAttendees(CalendarOrganizer? organizer, List? attendees) { - final listEmailAddressAttendees = attendees - ?.map((attendee) => EmailAddress(attendee.name?.name, attendee.mailto?.mailAddress.value)) - .toList() ?? []; + List listEmailAddressAttendees = []; if (organizer != null) { - listEmailAddressAttendees.add(EmailAddress(organizer.name, organizer.mailto?.value)); + listEmailAddressAttendees.add(organizer.toEmailAddress()); } - final listEmailAddressMailTo = listEmailAddressAttendees - .where((emailAddress) => emailAddress.emailAddress.isNotEmpty && emailAddress.emailAddress != mailboxDashBoardController.sessionCurrent?.username.value) - .toSet() - .toList(); + final listEmailAddress = attendees + ?.map((attendee) => attendee.toEmailAddress()) + .toList() ?? []; + listEmailAddressAttendees.addAll(listEmailAddress); + + final username = mailboxDashBoardController.sessionCurrent?.username.value ?? ''; + final listEmailAddressMailTo = listEmailAddressAttendees.removeInvalidEmails(username); log('SingleEmailController::handleMailToAttendees: listEmailAddressMailTo = $listEmailAddressMailTo'); mailboxDashBoardController.goToComposer( ComposerArguments.fromMailtoUri(listEmailAddress: listEmailAddressMailTo) diff --git a/lib/features/email/presentation/extensions/calendar_attendee_extension.dart b/lib/features/email/presentation/extensions/calendar_attendee_extension.dart new file mode 100644 index 0000000000..8233445363 --- /dev/null +++ b/lib/features/email/presentation/extensions/calendar_attendee_extension.dart @@ -0,0 +1,12 @@ + +import 'package:jmap_dart_client/jmap/mail/calendar/properties/attendee/calendar_attendee.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; + +extension CalendarAttendeeExtension on CalendarAttendee { + EmailAddress toEmailAddress() { + return EmailAddress( + name?.name, + mailto?.mailAddress.value, + ); + } +} \ No newline at end of file diff --git a/lib/features/email/presentation/extensions/calendar_organizer_extension.dart b/lib/features/email/presentation/extensions/calendar_organizer_extension.dart new file mode 100644 index 0000000000..173345b5c0 --- /dev/null +++ b/lib/features/email/presentation/extensions/calendar_organizer_extension.dart @@ -0,0 +1,12 @@ + +import 'package:jmap_dart_client/jmap/mail/calendar/properties/calendar_organizer.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; + +extension CalendarOrganizerExtension on CalendarOrganizer { + EmailAddress toEmailAddress() { + return EmailAddress( + name, + mailto?.value, + ); + } +} \ No newline at end of file diff --git a/model/lib/extensions/list_email_address_extension.dart b/model/lib/extensions/list_email_address_extension.dart index 84a9465bf3..2678b9efcd 100644 --- a/model/lib/extensions/list_email_address_extension.dart +++ b/model/lib/extensions/list_email_address_extension.dart @@ -38,4 +38,13 @@ extension SetEmailAddressExtension on Set? { extension ListEmailAddressExtension on List { Set asSetAddress() => map((emailAddress) => emailAddress.emailAddress).toSet(); + + List removeInvalidEmails(String username) { + final Set seenEmails = {}; + return where((email) { + if (email.emailAddress.isEmpty) return false; + if (email.emailAddress == username) return false; + return seenEmails.add(email.emailAddress); + }).toList(); + } } \ No newline at end of file diff --git a/model/test/extensions/list_email_address_extension_test.dart b/model/test/extensions/list_email_address_extension_test.dart new file mode 100644 index 0000000000..3319d60933 --- /dev/null +++ b/model/test/extensions/list_email_address_extension_test.dart @@ -0,0 +1,71 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:model/extensions/email_address_extension.dart'; +import 'package:model/extensions/list_email_address_extension.dart'; + +void main() { + group('ListEmailAddressExtension::removeInvalidEmails::test', () { + test('SHOULD remove email addresses that are empty', () { + final emails = [ + EmailAddress('Alice', 'alice@example.com'), + EmailAddress('Bob', ''), + EmailAddress('Charlie', 'charlie@example.com'), + ]; + + final validEmails = emails.removeInvalidEmails('bob@example.com'); + + expect(validEmails.length, 2); + expect(validEmails[0].emailAddress, 'alice@example.com'); + expect(validEmails[1].emailAddress, 'charlie@example.com'); + }); + + test('SHOULD remove email addresses that match the provided username', () { + final emails = [ + EmailAddress('Alice', 'alice@example.com'), + EmailAddress('Bob', 'bob@example.com'), + EmailAddress('Charlie', 'charlie@example.com'), + ]; + + final validEmails = emails.removeInvalidEmails('bob@example.com'); + + expect(validEmails.length, 2); + expect(validEmails[0].emailAddress, 'alice@example.com'); + expect(validEmails[1].emailAddress, 'charlie@example.com'); + }); + + test('SHOULD remove duplicate email addresses, keeping only the first occurrence', () { + final emails = [ + EmailAddress('Alice', 'alice@example.com'), + EmailAddress('Bob', 'bob@example.com'), + EmailAddress('Charlie', 'alice@example.com'), + EmailAddress('David', 'david@example.com'), + ]; + + final validEmails = emails.removeInvalidEmails('bob@example.com'); + + expect(validEmails.length, 2); + expect(validEmails[0].emailAddress, 'alice@example.com'); + expect(validEmails[1].emailAddress, 'david@example.com'); + }); + + test('SHOULD return an empty list if all email addresses are invalid', () { + final emails = [ + EmailAddress('Alice', ''), + EmailAddress('Bob', 'bob@example.com'), + EmailAddress('Charlie', 'bob@example.com'), + ]; + + final validEmails = emails.removeInvalidEmails('bob@example.com'); + + expect(validEmails.isEmpty, true); + }); + + test('SHOULD return an empty list for an empty input list', () { + final emails = []; + + final validEmails = emails.removeInvalidEmails('bob@example.com'); + + expect(validEmails.isEmpty, true); + }); + }); +}