From caa7908f19fc838b943d9f28d96540f8b8f2c0b5 Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 21 Apr 2025 13:38:50 +0700 Subject: [PATCH] TF-3674 Fix logic reply email Signed-off-by: dab246 --- .../presentation/composer_controller.dart | 8 +- .../presentation_email_extension.dart | 104 ++++++++--- .../presentation_email_extension_test.dart | 174 ++++++++++++------ 3 files changed, 203 insertions(+), 83 deletions(-) diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index e62f0b9a3..6f5960abf 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -682,10 +682,10 @@ class ComposerController extends BaseController listPost: listPost, ); - listToEmailAddress = List.from(recipients.value1); - listCcEmailAddress = List.from(recipients.value2); - listBccEmailAddress = List.from(recipients.value3); - listReplyToEmailAddress = List.from(recipients.value4); + listToEmailAddress = List.from(recipients.to); + listCcEmailAddress = List.from(recipients.cc); + listBccEmailAddress = List.from(recipients.bcc); + listReplyToEmailAddress = List.from(recipients.replyTo); if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty || listReplyToEmailAddress.isNotEmpty) { isInitialRecipient.value = true; diff --git a/lib/features/email/presentation/extensions/presentation_email_extension.dart b/lib/features/email/presentation/extensions/presentation_email_extension.dart index 39d06001f..385a4c61f 100644 --- a/lib/features/email/presentation/extensions/presentation_email_extension.dart +++ b/lib/features/email/presentation/extensions/presentation_email_extension.dart @@ -1,4 +1,3 @@ -import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/email/presentation_email.dart'; @@ -6,7 +5,12 @@ import 'package:model/extensions/list_email_address_extension.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; extension PresentationEmailExtension on PresentationEmail { - Tuple4, List, List, List> generateRecipientsEmailAddressForComposer({ + ({ + List to, + List cc, + List bcc, + List replyTo, + }) generateRecipientsEmailAddressForComposer({ required EmailActionType emailActionType, bool isSender = false, String? userName, @@ -27,6 +31,7 @@ extension PresentationEmailExtension on PresentationEmail { newBccAddress: newBccAddress, newReplyToAddress: newReplyToAddress, userName: userName, + listPost: listPost, ); case EmailActionType.replyToList: @@ -41,39 +46,71 @@ extension PresentationEmailExtension on PresentationEmail { newReplyToAddress: newReplyToAddress, newFromAddress: newFromAddress, userName: userName, + listPost: listPost, ); default: - return Tuple4(newToAddress, newCcAddress, newBccAddress, newReplyToAddress); + return ( + to: newToAddress, + cc: newCcAddress, + bcc: newBccAddress, + replyTo: newReplyToAddress, + ); } } - Tuple4, List, List, List> _handleReply({ + ({ + List to, + List cc, + List bcc, + List replyTo, + }) _handleReply({ required bool isSender, required List newToAddress, required List newFromAddress, required List newBccAddress, required List newReplyToAddress, String? userName, + String? listPost, }) { - if (isSender) return Tuple4(newToAddress, [], [], []); + if (isSender) return (to: newToAddress, cc: [], bcc: [], replyTo: []); - final listToAddress = (newReplyToAddress.isNotEmpty ? newReplyToAddress : newFromAddress).withoutMe(userName); - return Tuple4(listToAddress, [], [], []); + final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(listPost ?? ''); + List listToAddress = []; + if (isReplyToListEnabled) { + listToAddress = newFromAddress.withoutMe(userName); + } else { + listToAddress = (newReplyToAddress.isNotEmpty + ? newReplyToAddress + : newFromAddress + ).withoutMe(userName); + } + + return (to: listToAddress, cc: [], bcc: [], replyTo: []); } - Tuple4, List, List, List> _handleReplyToList(String? listPost, String? userName) { + ({ + List to, + List cc, + List bcc, + List replyTo, + }) _handleReplyToList(String? listPost, String? userName) { final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? ''); - return Tuple4( - recipientRecord.toMailAddresses.removeDuplicateEmails().withoutMe(userName), - recipientRecord.ccMailAddresses.removeDuplicateEmails().withoutMe(userName), - recipientRecord.bccMailAddresses.removeDuplicateEmails().withoutMe(userName), - [], + return ( + to: recipientRecord.toMailAddresses.removeDuplicateEmails().withoutMe(userName), + cc: recipientRecord.ccMailAddresses.removeDuplicateEmails().withoutMe(userName), + bcc: recipientRecord.bccMailAddresses.removeDuplicateEmails().withoutMe(userName), + replyTo: [], ); } - Tuple4, List, List, List> _handleReplyAll({ + ({ + List to, + List cc, + List bcc, + List replyTo, + }) _handleReplyAll({ required bool isSender, required List newToAddress, required List newCcAddress, @@ -81,22 +118,39 @@ extension PresentationEmailExtension on PresentationEmail { required List newReplyToAddress, required List newFromAddress, String? userName, + String? listPost, }) { if (isSender) { - return Tuple4(newToAddress, newCcAddress, newBccAddress, newReplyToAddress); + return ( + to: newToAddress, + cc: newCcAddress, + bcc: newBccAddress, + replyTo: newReplyToAddress, + ); } - final listToAddress = { - ...(newReplyToAddress.isNotEmpty ? newReplyToAddress : newFromAddress), - ...newToAddress, - }.removeDuplicateEmails().withoutMe(userName); + final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(listPost ?? ''); + List listToAddress = []; - return Tuple4( - listToAddress, - newCcAddress.withoutMe(userName), - newBccAddress.withoutMe(userName), - [], + if (isReplyToListEnabled) { + listToAddress = { + ...newReplyToAddress, + ...newFromAddress, + ...newToAddress, + }.removeDuplicateEmails().withoutMe(userName); + + } else { + listToAddress = { + ...(newReplyToAddress.isNotEmpty ? newReplyToAddress : newFromAddress), + ...newToAddress, + }.removeDuplicateEmails().withoutMe(userName); + } + + return ( + to: listToAddress, + cc: newCcAddress.withoutMe(userName), + bcc: newBccAddress.withoutMe(userName), + replyTo: [], ); } - } \ No newline at end of file diff --git a/test/model/lib/extensions/presentation_email_extension_test.dart b/test/model/lib/extensions/presentation_email_extension_test.dart index 786c93458..a45dbb700 100644 --- a/test/model/lib/extensions/presentation_email_extension_test.dart +++ b/test/model/lib/extensions/presentation_email_extension_test.dart @@ -45,10 +45,10 @@ void main() { userName: userAEmailAddress.emailAddress, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); test( @@ -75,10 +75,10 @@ void main() { userName: userAEmailAddress.emailAddress, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); }); @@ -113,10 +113,10 @@ void main() { listPost: listPost, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); test( @@ -145,10 +145,10 @@ void main() { userName: userAEmailAddress.emailAddress, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); }); @@ -175,10 +175,10 @@ void main() { listPost: listPost, ); - expect(result.value1, equals([userBEmailAddress, userAEmailAddress])); - expect(result.value2, isEmpty); - expect(result.value3, isEmpty); - expect(result.value4, isEmpty); + expect(result.to, equals([userBEmailAddress, userAEmailAddress])); + expect(result.cc, isEmpty); + expect(result.bcc, isEmpty); + expect(result.replyTo, isEmpty); }); test( @@ -208,10 +208,10 @@ void main() { listPost: listPost, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); test( @@ -240,10 +240,10 @@ void main() { userName: userAEmailAddress.emailAddress, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); }); @@ -252,6 +252,7 @@ void main() { 'AND send an email to user A and user E, cc to user C, bcc to user D', () { test( + 'Email without the List-Post header' 'THEN user A click reply, generateRecipientsEmailAddressForComposer\n' 'SHOULD return only replyToEmailAddress email to reply' , () { @@ -275,18 +276,51 @@ void main() { isSender: false, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); test( + 'Email has the List-Post header' + 'THEN user A click reply, generateRecipientsEmailAddressForComposer\n' + 'SHOULD return only user B email to reply' , + () { + final expectedResult = Tuple4( + [userBEmailAddress], + [], + [], + [], + ); + + final emailToReply = PresentationEmail( + from: {userBEmailAddress}, + replyTo: {replyToEmailAddress}, + to: {userAEmailAddress, userEEmailAddress}, + cc: {userCEmailAddress}, + bcc: {userDEmailAddress} + ); + + final result = emailToReply.generateRecipientsEmailAddressForComposer( + emailActionType: EmailActionType.reply, + isSender: false, + listPost: listPost, + ); + + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); + }); + + test( + 'Email without the List-Post header' 'THEN user A clicks reply all, generateRecipientsEmailAddressForComposer\n' 'SHOULD return replyToEmailAddress + user A email + user E email to reply, user C email address to cc, user D email address to bcc', () { final expectedResult = Tuple4( - [userAEmailAddress, userEEmailAddress, replyToEmailAddress], + [replyToEmailAddress, userAEmailAddress, userEEmailAddress], [userCEmailAddress], [userDEmailAddress], [], @@ -305,10 +339,42 @@ void main() { isSender: false, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); + }); + + test( + 'Email has the List-Post header' + 'THEN user A clicks reply all, generateRecipientsEmailAddressForComposer\n' + 'SHOULD return replyToEmailAddress + user B email + user A email + user E email to reply, user C email address to cc, user D email address to bcc', + () { + final expectedResult = Tuple4( + [replyToEmailAddress, userBEmailAddress, userAEmailAddress, userEEmailAddress], + [userCEmailAddress], + [userDEmailAddress], + [], + ); + + final emailToReply = PresentationEmail( + from: {userBEmailAddress}, + replyTo: {replyToEmailAddress}, + to: {userAEmailAddress, userEEmailAddress}, + cc: {userCEmailAddress}, + bcc: {userDEmailAddress} + ); + + final result = emailToReply.generateRecipientsEmailAddressForComposer( + emailActionType: EmailActionType.replyAll, + isSender: false, + listPost: listPost, + ); + + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); }); @@ -339,10 +405,10 @@ void main() { isSender: false, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); test( @@ -350,7 +416,7 @@ void main() { 'SHOULD return user A email + user E email + user B email to reply, user C email to cc, user D email to bcc', () { final expectedResult = Tuple4( - [userAEmailAddress, userEEmailAddress, userBEmailAddress], + [userBEmailAddress, userAEmailAddress, userEEmailAddress], [userCEmailAddress], [userDEmailAddress], [], @@ -368,10 +434,10 @@ void main() { isSender: false, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); test( @@ -394,10 +460,10 @@ void main() { listPost: listPost, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); }); @@ -429,10 +495,10 @@ void main() { isSender: false, ); - expect(result.value1, containsAll(expectedResult.value1)); - expect(result.value2, containsAll(expectedResult.value2)); - expect(result.value3, containsAll(expectedResult.value3)); - expect(result.value4, containsAll(expectedResult.value4)); + expect(result.to, equals(expectedResult.value1)); + expect(result.cc, equals(expectedResult.value2)); + expect(result.bcc, equals(expectedResult.value3)); + expect(result.replyTo, equals(expectedResult.value4)); }); }); });