TF-3674 Fix logic reply email

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-04-21 13:38:50 +07:00
committed by Dat H. Pham
parent 611d446f7b
commit caa7908f19
3 changed files with 203 additions and 83 deletions
@@ -682,10 +682,10 @@ class ComposerController extends BaseController
listPost: listPost, listPost: listPost,
); );
listToEmailAddress = List.from(recipients.value1); listToEmailAddress = List.from(recipients.to);
listCcEmailAddress = List.from(recipients.value2); listCcEmailAddress = List.from(recipients.cc);
listBccEmailAddress = List.from(recipients.value3); listBccEmailAddress = List.from(recipients.bcc);
listReplyToEmailAddress = List.from(recipients.value4); listReplyToEmailAddress = List.from(recipients.replyTo);
if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty || listReplyToEmailAddress.isNotEmpty) { if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty || listReplyToEmailAddress.isNotEmpty) {
isInitialRecipient.value = true; isInitialRecipient.value = true;
@@ -1,4 +1,3 @@
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/email_action_type.dart'; import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.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'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
extension PresentationEmailExtension on PresentationEmail { extension PresentationEmailExtension on PresentationEmail {
Tuple4<List<EmailAddress>, List<EmailAddress>, List<EmailAddress>, List<EmailAddress>> generateRecipientsEmailAddressForComposer({ ({
List<EmailAddress> to,
List<EmailAddress> cc,
List<EmailAddress> bcc,
List<EmailAddress> replyTo,
}) generateRecipientsEmailAddressForComposer({
required EmailActionType emailActionType, required EmailActionType emailActionType,
bool isSender = false, bool isSender = false,
String? userName, String? userName,
@@ -27,6 +31,7 @@ extension PresentationEmailExtension on PresentationEmail {
newBccAddress: newBccAddress, newBccAddress: newBccAddress,
newReplyToAddress: newReplyToAddress, newReplyToAddress: newReplyToAddress,
userName: userName, userName: userName,
listPost: listPost,
); );
case EmailActionType.replyToList: case EmailActionType.replyToList:
@@ -41,39 +46,71 @@ extension PresentationEmailExtension on PresentationEmail {
newReplyToAddress: newReplyToAddress, newReplyToAddress: newReplyToAddress,
newFromAddress: newFromAddress, newFromAddress: newFromAddress,
userName: userName, userName: userName,
listPost: listPost,
); );
default: default:
return Tuple4(newToAddress, newCcAddress, newBccAddress, newReplyToAddress); return (
to: newToAddress,
cc: newCcAddress,
bcc: newBccAddress,
replyTo: newReplyToAddress,
);
} }
} }
Tuple4<List<EmailAddress>, List<EmailAddress>, List<EmailAddress>, List<EmailAddress>> _handleReply({ ({
List<EmailAddress> to,
List<EmailAddress> cc,
List<EmailAddress> bcc,
List<EmailAddress> replyTo,
}) _handleReply({
required bool isSender, required bool isSender,
required List<EmailAddress> newToAddress, required List<EmailAddress> newToAddress,
required List<EmailAddress> newFromAddress, required List<EmailAddress> newFromAddress,
required List<EmailAddress> newBccAddress, required List<EmailAddress> newBccAddress,
required List<EmailAddress> newReplyToAddress, required List<EmailAddress> newReplyToAddress,
String? userName, 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); final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(listPost ?? '');
return Tuple4(listToAddress, [], [], []); List<EmailAddress> listToAddress = [];
if (isReplyToListEnabled) {
listToAddress = newFromAddress.withoutMe(userName);
} else {
listToAddress = (newReplyToAddress.isNotEmpty
? newReplyToAddress
: newFromAddress
).withoutMe(userName);
}
return (to: listToAddress, cc: [], bcc: [], replyTo: []);
} }
Tuple4<List<EmailAddress>, List<EmailAddress>, List<EmailAddress>, List<EmailAddress>> _handleReplyToList(String? listPost, String? userName) { ({
List<EmailAddress> to,
List<EmailAddress> cc,
List<EmailAddress> bcc,
List<EmailAddress> replyTo,
}) _handleReplyToList(String? listPost, String? userName) {
final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? ''); final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? '');
return Tuple4( return (
recipientRecord.toMailAddresses.removeDuplicateEmails().withoutMe(userName), to: recipientRecord.toMailAddresses.removeDuplicateEmails().withoutMe(userName),
recipientRecord.ccMailAddresses.removeDuplicateEmails().withoutMe(userName), cc: recipientRecord.ccMailAddresses.removeDuplicateEmails().withoutMe(userName),
recipientRecord.bccMailAddresses.removeDuplicateEmails().withoutMe(userName), bcc: recipientRecord.bccMailAddresses.removeDuplicateEmails().withoutMe(userName),
[], replyTo: [],
); );
} }
Tuple4<List<EmailAddress>, List<EmailAddress>, List<EmailAddress>, List<EmailAddress>> _handleReplyAll({ ({
List<EmailAddress> to,
List<EmailAddress> cc,
List<EmailAddress> bcc,
List<EmailAddress> replyTo,
}) _handleReplyAll({
required bool isSender, required bool isSender,
required List<EmailAddress> newToAddress, required List<EmailAddress> newToAddress,
required List<EmailAddress> newCcAddress, required List<EmailAddress> newCcAddress,
@@ -81,22 +118,39 @@ extension PresentationEmailExtension on PresentationEmail {
required List<EmailAddress> newReplyToAddress, required List<EmailAddress> newReplyToAddress,
required List<EmailAddress> newFromAddress, required List<EmailAddress> newFromAddress,
String? userName, String? userName,
String? listPost,
}) { }) {
if (isSender) { if (isSender) {
return Tuple4(newToAddress, newCcAddress, newBccAddress, newReplyToAddress); return (
to: newToAddress,
cc: newCcAddress,
bcc: newBccAddress,
replyTo: newReplyToAddress,
);
} }
final listToAddress = { final isReplyToListEnabled = EmailUtils.isReplyToListEnabled(listPost ?? '');
...(newReplyToAddress.isNotEmpty ? newReplyToAddress : newFromAddress), List<EmailAddress> listToAddress = [];
...newToAddress,
}.removeDuplicateEmails().withoutMe(userName);
return Tuple4( if (isReplyToListEnabled) {
listToAddress, listToAddress = {
newCcAddress.withoutMe(userName), ...newReplyToAddress,
newBccAddress.withoutMe(userName), ...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: [],
); );
} }
} }
@@ -45,10 +45,10 @@ void main() {
userName: userAEmailAddress.emailAddress, userName: userAEmailAddress.emailAddress,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
test( test(
@@ -75,10 +75,10 @@ void main() {
userName: userAEmailAddress.emailAddress, userName: userAEmailAddress.emailAddress,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
}); });
@@ -113,10 +113,10 @@ void main() {
listPost: listPost, listPost: listPost,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
test( test(
@@ -145,10 +145,10 @@ void main() {
userName: userAEmailAddress.emailAddress, userName: userAEmailAddress.emailAddress,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
}); });
@@ -175,10 +175,10 @@ void main() {
listPost: listPost, listPost: listPost,
); );
expect(result.value1, equals([userBEmailAddress, userAEmailAddress])); expect(result.to, equals([userBEmailAddress, userAEmailAddress]));
expect(result.value2, isEmpty); expect(result.cc, isEmpty);
expect(result.value3, isEmpty); expect(result.bcc, isEmpty);
expect(result.value4, isEmpty); expect(result.replyTo, isEmpty);
}); });
test( test(
@@ -208,10 +208,10 @@ void main() {
listPost: listPost, listPost: listPost,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
test( test(
@@ -240,10 +240,10 @@ void main() {
userName: userAEmailAddress.emailAddress, userName: userAEmailAddress.emailAddress,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); 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', 'AND send an email to user A and user E, cc to user C, bcc to user D',
() { () {
test( test(
'Email without the List-Post header'
'THEN user A click reply, generateRecipientsEmailAddressForComposer\n' 'THEN user A click reply, generateRecipientsEmailAddressForComposer\n'
'SHOULD return only replyToEmailAddress email to reply' , 'SHOULD return only replyToEmailAddress email to reply' ,
() { () {
@@ -275,18 +276,51 @@ void main() {
isSender: false, isSender: false,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
test( 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],
<EmailAddress>[],
<EmailAddress>[],
<EmailAddress>[],
);
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' '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', '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( final expectedResult = Tuple4(
[userAEmailAddress, userEEmailAddress, replyToEmailAddress], [replyToEmailAddress, userAEmailAddress, userEEmailAddress],
<EmailAddress>[userCEmailAddress], <EmailAddress>[userCEmailAddress],
<EmailAddress>[userDEmailAddress], <EmailAddress>[userDEmailAddress],
<EmailAddress>[], <EmailAddress>[],
@@ -305,10 +339,42 @@ void main() {
isSender: false, isSender: false,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); 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],
<EmailAddress>[userCEmailAddress],
<EmailAddress>[userDEmailAddress],
<EmailAddress>[],
);
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, isSender: false,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
test( 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', '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( final expectedResult = Tuple4(
[userAEmailAddress, userEEmailAddress, userBEmailAddress], [userBEmailAddress, userAEmailAddress, userEEmailAddress],
<EmailAddress>[userCEmailAddress], <EmailAddress>[userCEmailAddress],
<EmailAddress>[userDEmailAddress], <EmailAddress>[userDEmailAddress],
<EmailAddress>[], <EmailAddress>[],
@@ -368,10 +434,10 @@ void main() {
isSender: false, isSender: false,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
test( test(
@@ -394,10 +460,10 @@ void main() {
listPost: listPost, listPost: listPost,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
}); });
@@ -429,10 +495,10 @@ void main() {
isSender: false, isSender: false,
); );
expect(result.value1, containsAll(expectedResult.value1)); expect(result.to, equals(expectedResult.value1));
expect(result.value2, containsAll(expectedResult.value2)); expect(result.cc, equals(expectedResult.value2));
expect(result.value3, containsAll(expectedResult.value3)); expect(result.bcc, equals(expectedResult.value3));
expect(result.value4, containsAll(expectedResult.value4)); expect(result.replyTo, equals(expectedResult.value4));
}); });
}); });
}); });