diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index e5a0df67b..2e4887c67 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -23,7 +23,6 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart'; -import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/model.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; @@ -647,8 +646,6 @@ class ComposerController extends BaseController _initEmailAddress( presentationEmail: arguments.presentationEmail!, actionType: arguments.emailActionType, - mailboxRole: arguments.presentationEmail!.mailboxContain?.role - ?? mailboxDashBoardController.selectedMailbox.value?.role, listPost: arguments.listPost, ); _initSubjectEmail( @@ -802,32 +799,23 @@ class ComposerController extends BaseController void _initEmailAddress({ required PresentationEmail presentationEmail, required EmailActionType actionType, - Role? mailboxRole, String? listPost, }) { - log('ComposerController::_initEmailAddress:listPost = $listPost'); + final userName = mailboxDashBoardController.sessionCurrent?.username.value; + final isSender = presentationEmail.from + .asList() + .any((element) => element.emailAddress.isNotEmpty && element.emailAddress == userName); + final recipients = presentationEmail.generateRecipientsEmailAddressForComposer( emailActionType: actionType, - mailboxRole: mailboxRole, + isSender: isSender, + userName: userName, listPost: listPost, ); - final userName = mailboxDashBoardController.sessionCurrent?.username; - if (userName != null) { - final isSender = presentationEmail.from.asList().every((element) => element.email == userName.value); - if (isSender) { - listToEmailAddress = List.from(recipients.value1.toSet()); - listCcEmailAddress = List.from(recipients.value2.toSet()); - listBccEmailAddress = List.from(recipients.value3.toSet()); - } else { - listToEmailAddress = List.from(recipients.value1.toSet().filterEmailAddress(userName.value)); - listCcEmailAddress = List.from(recipients.value2.toSet().filterEmailAddress(userName.value)); - listBccEmailAddress = List.from(recipients.value3.toSet().filterEmailAddress(userName.value)); - } - } else { - listToEmailAddress = List.from(recipients.value1.toSet()); - listCcEmailAddress = List.from(recipients.value2.toSet()); - listBccEmailAddress = List.from(recipients.value3.toSet()); - } + + listToEmailAddress = List.from(recipients.value1); + listCcEmailAddress = List.from(recipients.value2); + listBccEmailAddress = List.from(recipients.value3); if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty) { isInitialRecipient.value = true; diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index d32c7d614..7b3194df8 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -1422,6 +1422,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxRole: presentationEmail.mailboxContain?.role, messageId: currentEmailLoaded.value?.emailCurrent?.messageId, references: currentEmailLoaded.value?.emailCurrent?.references, + listPost: currentEmailLoaded.value?.emailCurrent?.listPost, ) ); break; @@ -1448,6 +1449,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxRole: presentationEmail.mailboxContain?.role, messageId: currentEmailLoaded.value?.emailCurrent?.messageId, references: currentEmailLoaded.value?.emailCurrent?.references, + listPost: currentEmailLoaded.value?.emailCurrent?.listPost, ) ); break; diff --git a/lib/features/email/presentation/extensions/presentation_email_extension.dart b/lib/features/email/presentation/extensions/presentation_email_extension.dart index 017c7a632..a2427a310 100644 --- a/lib/features/email/presentation/extensions/presentation_email_extension.dart +++ b/lib/features/email/presentation/extensions/presentation_email_extension.dart @@ -1,49 +1,91 @@ -import 'package:core/utils/app_logger.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; -import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/email/presentation_email.dart'; import 'package:model/extensions/list_email_address_extension.dart'; -import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; extension PresentationEmailExtension on PresentationEmail { Tuple3, List, List> generateRecipientsEmailAddressForComposer({ required EmailActionType emailActionType, - Role? mailboxRole, + bool isSender = false, + String? userName, String? listPost, }) { + final newFromAddress = from.removeDuplicateEmails(); + final newToAddress = to.removeDuplicateEmails(); + final newCcAddress = cc.removeDuplicateEmails(); + final newBccAddress = bcc.removeDuplicateEmails(); + final newReplyToAddress = replyTo.removeDuplicateEmails(); + switch (emailActionType) { case EmailActionType.reply: - if (mailboxRole == PresentationMailbox.roleSent) { - return Tuple3(to.asList(), [], []); - } else { - final replyToAddress = replyTo.asList().isNotEmpty - ? replyTo.asList() - : from.asList(); - return Tuple3(replyToAddress, [], []); - } + final listReplyAddress = isSender ? newToAddress : newFromAddress; + final listReplyAddressWithoutUsername = listReplyAddress.withoutMe(userName); + + return Tuple3(listReplyAddressWithoutUsername, [], []); case EmailActionType.replyToList: - final listEmailAddress = EmailUtils.parsingListPost(listPost ?? '') ?? []; - log('PresentationEmailExtension::generateRecipientsEmailAddressForComposer:listEmailAddress = $listEmailAddress'); - return Tuple3(listEmailAddress, [], []); + final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? ''); + + final listToAddressWithoutUsername = recipientRecord.toMailAddresses + .toSet() + .removeDuplicateEmails() + .withoutMe(userName); + + final listCcAddressWithoutUsername = recipientRecord.ccMailAddresses + .toSet() + .removeDuplicateEmails() + .withoutMe(userName); + + final listBccAddressWithoutUsername = recipientRecord.bccMailAddresses + .toSet() + .removeDuplicateEmails() + .withoutMe(userName); + + return Tuple3( + listToAddressWithoutUsername, + listCcAddressWithoutUsername, + listBccAddressWithoutUsername, + ); case EmailActionType.replyAll: - if (mailboxRole == PresentationMailbox.roleSent) { - return Tuple3(to.asList(), cc.asList(), bcc.asList()); - } else { - final senderReplyToAddress = replyTo.asList().isNotEmpty - ? replyTo.asList() - : from.asList(); - return Tuple3( - to.asList() + senderReplyToAddress, - cc.asList(), - bcc.asList(), - ); - } + final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? ''); + + final listToAddress = recipientRecord.toMailAddresses + + newReplyToAddress + + newFromAddress + + newToAddress; + final listCcAddress = recipientRecord.ccMailAddresses + newCcAddress; + final listBccAddress = recipientRecord.bccMailAddresses + newBccAddress; + + final listToAddressWithoutUsername = listToAddress + .toSet() + .removeDuplicateEmails() + .withoutMe(userName); + final listCcAddressWithoutUsername = listCcAddress + .toSet() + .removeDuplicateEmails() + .withoutMe(userName); + final listBccAddressWithoutUsername = listBccAddress + .toSet() + .removeDuplicateEmails() + .withoutMe(userName); + + return Tuple3( + listToAddressWithoutUsername, + listCcAddressWithoutUsername, + listBccAddressWithoutUsername, + ); default: - return Tuple3(to.asList(), cc.asList(), bcc.asList()); + final listToAddressWithoutUsername = newToAddress.withoutMe(userName); + final listCcAddressWithoutUsername = newCcAddress.withoutMe(userName); + final listBccAddressWithoutUsername = newBccAddress.withoutMe(userName); + + return Tuple3( + listToAddressWithoutUsername, + listCcAddressWithoutUsername, + listBccAddressWithoutUsername, + ); } } } \ No newline at end of file diff --git a/lib/features/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index 8b5744619..25ce2fe91 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -122,6 +122,7 @@ class ComposerArguments extends RouterArguments { Role? mailboxRole, MessageIdsHeaderValue? messageId, MessageIdsHeaderValue? references, + String? listPost, }) => ComposerArguments( emailActionType: EmailActionType.reply, presentationEmail: presentationEmail, @@ -130,6 +131,7 @@ class ComposerArguments extends RouterArguments { mailboxRole: mailboxRole, messageId: messageId, references: references, + listPost: listPost, ); factory ComposerArguments.replyToListEmail({ @@ -158,6 +160,7 @@ class ComposerArguments extends RouterArguments { Role? mailboxRole, MessageIdsHeaderValue? messageId, MessageIdsHeaderValue? references, + String? listPost, }) => ComposerArguments( emailActionType: EmailActionType.replyAll, presentationEmail: presentationEmail, @@ -166,6 +169,7 @@ class ComposerArguments extends RouterArguments { mailboxRole: mailboxRole, messageId: messageId, references: references, + listPost: listPost, ); factory ComposerArguments.forwardEmail({ diff --git a/lib/features/email/presentation/utils/email_utils.dart b/lib/features/email/presentation/utils/email_utils.dart index 964af35c2..17b8e648b 100644 --- a/lib/features/email/presentation/utils/email_utils.dart +++ b/lib/features/email/presentation/utils/email_utils.dart @@ -86,37 +86,108 @@ class EmailUtils { } } - static List? parsingListPost(String listPost) { + static List extractMailtoLinksFromListPost(String listPost) { try { - if (listPost.isEmpty) { - return null; + if (listPost.trim().isEmpty) return []; + + final decodedInput = Uri.decodeComponent(listPost); + + final mailtoRegex = RegExp(r'<(mailto:[^<>]+)>'); + + final matches = mailtoRegex.allMatches(decodedInput); + + if (matches.isEmpty) { + log('EmailUtils::extractMailtoLinksFromListPost: Not found mailto link'); + return []; } - final regExpMailtoLinks = RegExp(r'mailto:([^>,]*)'); - final allMatchesMailtoLinks = regExpMailtoLinks.allMatches(listPost); - final listMailtoLinks = allMatchesMailtoLinks - .map((match) => match.group(0)) - .whereNotNull() - .toList(); - log('EmailUtils::parsingListPost:listMailtoLinks: $listMailtoLinks'); - - if (listMailtoLinks.isNotEmpty) { - return listMailtoLinks - .map((mailto) { - final mapMailto = RouteUtils.parseMapMailtoFromUri(mailto); - final emailAddress = mapMailto[RouteUtils.paramMailtoAddress]; - return emailAddress != null - ? EmailAddress(null, emailAddress) - : null; - }) - .whereNotNull() - .toList(); - } else { - return null; - } + return matches.map((match) => match.group(1)!).toList(); } catch (e) { - logError('EmailUtils::parsingListPost:Exception = $e'); - return null; + logError('EmailUtils::extractMailtoLinksFromListPost:Exception = $e'); + return []; } } + + static ({ + List toMailAddresses, + List ccMailAddresses, + List bccMailAddresses, + }) extractRecipientsFromListMailtoLink(List mailtoLinks) { + try { + log('EmailUtils::extractRecipientsFromListMailtoLink: mailtoLinks: $mailtoLinks:'); + if (mailtoLinks.isEmpty) { + return ( + toMailAddresses: [], + ccMailAddresses: [], + bccMailAddresses: [], + ); + } + + final toMailAddresses = []; + final ccMailAddresses = []; + final bccMailAddresses = []; + + for (var mailtoLink in mailtoLinks) { + final recipientRecord = extractRecipientsFromMailtoLink(mailtoLink); + toMailAddresses.addAll(recipientRecord.toMailAddresses); + ccMailAddresses.addAll(recipientRecord.ccMailAddresses); + bccMailAddresses.addAll(recipientRecord.bccMailAddresses); + } + + return ( + toMailAddresses: toMailAddresses, + ccMailAddresses: ccMailAddresses, + bccMailAddresses: bccMailAddresses + ); + } catch (e) { + logError('EmailUtils::extractRecipientsFromListMailtoLink:Exception = $e'); + return ( + toMailAddresses: [], + ccMailAddresses: [], + bccMailAddresses: [], + ); + } + } + + static ({ + List toMailAddresses, + List ccMailAddresses, + List bccMailAddresses, + }) extractRecipientsFromMailtoLink(String mailtoLink) { + try { + log('EmailUtils::extractRecipientsFromMailtoLink:mailtoLink: $mailtoLink:'); + if (mailtoLink.isEmpty) { + return ( + toMailAddresses: [], + ccMailAddresses: [], + bccMailAddresses: [], + ); + } + + final navigationRouter = + RouteUtils.generateNavigationRouterFromMailtoLink(mailtoLink); + log('EmailUtils::extractRecipientsFromMailtoLink:navigationRouter = $navigationRouter'); + return ( + toMailAddresses: navigationRouter.listEmailAddress ?? [], + ccMailAddresses: navigationRouter.cc ?? [], + bccMailAddresses: navigationRouter.bcc ?? [], + ); + } catch (e) { + logError('EmailUtils::extractRecipientsFromMailtoLink:Exception = $e'); + return ( + toMailAddresses: [], + ccMailAddresses: [], + bccMailAddresses: [], + ); + } + } + + static ({ + List toMailAddresses, + List ccMailAddresses, + List bccMailAddresses, + }) extractRecipientsFromListPost(String listPost) { + final mailtoLinks = extractMailtoLinksFromListPost(listPost); + return extractRecipientsFromListMailtoLink(mailtoLinks); + } } \ 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 ebece29a4..8f6416794 100644 --- a/model/lib/extensions/list_email_address_extension.dart +++ b/model/lib/extensions/list_email_address_extension.dart @@ -51,8 +51,27 @@ extension SetEmailAddressExtension on Set? { Set withoutMe(String userName) { return filterEmailAddress(userName).toSet(); } + + List removeDuplicateEmails() { + final seenEmails = {}; + return this?.where((emailAddress) { + if (emailAddress.emailAddress.isEmpty || + seenEmails.contains(emailAddress.emailAddress)) { + return false; + } else { + seenEmails.add(emailAddress.emailAddress); + return true; + } + }).toList() ?? []; + } } extension ListEmailAddressExtension on List { Set asSetAddress() => map((emailAddress) => emailAddress.emailAddress).toSet(); + + List withoutMe(String? userName) { + if (userName == null) return this; + + return where((emailAddress) => emailAddress.emailAddress != userName).toList(); + } } \ No newline at end of file diff --git a/model/lib/extensions/presentation_email_extension.dart b/model/lib/extensions/presentation_email_extension.dart index 09b482786..9d6912aaa 100644 --- a/model/lib/extensions/presentation_email_extension.dart +++ b/model/lib/extensions/presentation_email_extension.dart @@ -52,7 +52,7 @@ extension PresentationEmailExtension on PresentationEmail { PresentationEmail toggleSelect() { return PresentationEmail( - id: this.id, + id: id, blobId: blobId, keywords: keywords, size: size, @@ -78,7 +78,7 @@ extension PresentationEmailExtension on PresentationEmail { PresentationEmail toSelectedEmail({required SelectMode selectMode}) { return PresentationEmail( - id: this.id, + id: id, blobId: blobId, keywords: keywords, size: size, @@ -104,7 +104,7 @@ extension PresentationEmailExtension on PresentationEmail { Email toEmail() { return Email( - id: this.id, + id: id, blobId: blobId, keywords: keywords, size: size, @@ -137,7 +137,7 @@ extension PresentationEmailExtension on PresentationEmail { final matchedMailbox = findMailboxContain(mapMailboxes); return PresentationEmail( - id: this.id, + id: id, blobId: blobId, keywords: keywords, size: size, @@ -176,7 +176,7 @@ extension PresentationEmailExtension on PresentationEmail { PresentationEmail withRouteWeb(Uri routeWeb) { return PresentationEmail( - id: this.id, + id: id, blobId: blobId, keywords: keywords, size: size, @@ -205,7 +205,7 @@ extension PresentationEmailExtension on PresentationEmail { combinedMap.removeWhere((key, value) => !value); log('PresentationEmailExtension::updateKeywords:combinedMap = $combinedMap'); return PresentationEmail( - id: this.id, + id: id, blobId: blobId, keywords: combinedMap, size: size, @@ -231,7 +231,7 @@ extension PresentationEmailExtension on PresentationEmail { PresentationEmail syncPresentationEmail({PresentationMailbox? mailboxContain, Uri? routeWeb}) { return PresentationEmail( - id: this.id, + id: id, blobId: blobId, keywords: keywords, size: size, diff --git a/test/features/email/extract_email_list_post_test.dart b/test/features/email/extract_email_list_post_test.dart new file mode 100644 index 000000000..82626f642 --- /dev/null +++ b/test/features/email/extract_email_list_post_test.dart @@ -0,0 +1,186 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; + +void main() { + group('EmailUtils::extractMailtoLinksFromListPost::', () { + test('should return a list of mailto links when valid mailto links are present', () { + const listPost = ', '; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, ['mailto:example1@test.com', 'mailto:example2@test.com']); + }); + + test('should return an empty list when no mailto links are present', () { + const listPost = ', '; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, isEmpty); + }); + + test('should return an empty list for an empty string input', () { + const listPost = ''; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, isEmpty); + }); + + test('should handle inputs with whitespace only', () { + const listPost = ' '; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, isEmpty); + }); + + test('should handle unexpected exceptions and return an empty list', () { + const listPost = '\uD800'; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, isEmpty); + }); + + test('should decode encoded URI input and extract mailto links', () { + const listPost = ', '; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, ['mailto:example1@test.com', 'mailto:example2@test.com']); + }); + + test('should handle mailto links with additional parameters like cc and bcc', () { + const listPost = ', '; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, ['mailto:johndoe@fakeemail.com', 'mailto:janedoe@fakeemail.com?cc=jackdoe@fakeemail.com&bcc=jennydoe@fakeemail.com']); + }); + + test('should handle mailto links with additional parameters like cc, bcc, subject and body', () { + const listPost = ', '; + final result = EmailUtils.extractMailtoLinksFromListPost(listPost); + + expect(result, [ + 'mailto:johndoe@fakeemail.com', + 'mailto:janedoe@fakeemail.com?cc=jackdoe@fakeemail.com&bcc=jennydoe@fakeemail.com&subject=TestSubject&body=TestBody', + ]); + }); + }); + + group('EmailUtils::extractRecipientsFromMailtoLink::', () { + test('should return empty lists for empty mailtoLink', () { + final result = EmailUtils.extractRecipientsFromMailtoLink(''); + expect(result.toMailAddresses, isEmpty); + expect(result.ccMailAddresses, isEmpty); + expect(result.bccMailAddresses, isEmpty); + }); + + test('should extract recipients from valid mailtoLink', () { + const mailtoLink = 'mailto:test@example.com?cc=cc@example.com&bcc=bcc@example.com'; + + final result = EmailUtils.extractRecipientsFromMailtoLink(mailtoLink); + + expect(result.toMailAddresses, [EmailAddress(null, 'test@example.com')]); + expect(result.ccMailAddresses, [EmailAddress(null, 'cc@example.com')]); + expect(result.bccMailAddresses, [EmailAddress(null, 'bcc@example.com')]); + }); + + test('should handle malformed mailtoLink gracefully', () { + const malformedMailtoLink = 'mailto:test@example.com?invalid=params'; + + final result = EmailUtils.extractRecipientsFromMailtoLink(malformedMailtoLink); + + expect(result.toMailAddresses, [EmailAddress(null, 'test@example.com')]); + expect(result.ccMailAddresses, isEmpty); + expect(result.bccMailAddresses, isEmpty); + }); + + test('should handle exceptions gracefully', () { + const invalidMailtoLink = 'mailto:invalid-link, mailto:%E0%A4%A'; + + final result = EmailUtils.extractRecipientsFromMailtoLink(invalidMailtoLink); + + expect(result.toMailAddresses, isEmpty); + expect(result.ccMailAddresses, isEmpty); + expect(result.bccMailAddresses, isEmpty); + }); + + test('should decode and extract recipients from encoded mailtoLink', () { + const encodedMailtoLink = 'mailto:test%40example.com?cc=cc1%40example.com%2Ccc2%40example.com&bcc=bcc%40example.com'; + + final result = EmailUtils.extractRecipientsFromMailtoLink(encodedMailtoLink); + + expect(result.toMailAddresses, [EmailAddress(null, 'test@example.com')]); + expect(result.ccMailAddresses, [EmailAddress(null, 'cc1@example.com'), EmailAddress(null, 'cc2@example.com')]); + expect(result.bccMailAddresses, [EmailAddress(null, 'bcc@example.com')]); + }); + + test('should extract recipients from mailto links with additional parameters like cc, bcc, subject and body', () { + const mailtoLink = 'mailto:test@example.com?cc=cc@example.com&bcc=bcc@example.com&subject=TestSubject&body=TestBody'; + + final result = EmailUtils.extractRecipientsFromMailtoLink(mailtoLink); + + expect(result.toMailAddresses, [EmailAddress(null, 'test@example.com')]); + expect(result.ccMailAddresses, [EmailAddress(null, 'cc@example.com')]); + expect(result.bccMailAddresses, [EmailAddress(null, 'bcc@example.com')]); + }); + }); + + group('EmailUtils::extractRecipientsFromListPost::', () { + test('should return empty lists for empty listPost', () { + final result = EmailUtils.extractRecipientsFromListPost(''); + + expect(result.toMailAddresses, isEmpty); + expect(result.ccMailAddresses, isEmpty); + expect(result.bccMailAddresses, isEmpty); + }); + + test('should extract recipients from a valid listPost', () { + const listPost = ', '; + + final result = EmailUtils.extractRecipientsFromListPost(listPost); + + expect(result.toMailAddresses, [ + EmailAddress(null, 'test@example.com'), + EmailAddress(null, 'another@example.com'), + ]); + expect(result.ccMailAddresses, [EmailAddress(null, 'cc@example.com')]); + expect(result.bccMailAddresses, [EmailAddress(null, 'bcc@example.com')]); + }); + + test('should handle listPost with no valid mailto links', () { + const listPost = 'content without mailto links'; + + final result = EmailUtils.extractRecipientsFromListPost(listPost); + + expect(result.toMailAddresses, isEmpty); + expect(result.ccMailAddresses, isEmpty); + expect(result.bccMailAddresses, isEmpty); + }); + + test('should decode and extract recipients from listPost with encoded mailto links', () { + const listPost = '%3Cmailto%3Atest%2540example.com%3Fcc%3Dcc1%2540example.com%252Ccc2%2540example.com%26bcc%3Dbcc%2540example.com%3E%2C%20%3Cmailto%3Aanother%2540example.com%3E'; + + final result = EmailUtils.extractRecipientsFromListPost(listPost); + + expect(result.toMailAddresses, [ + EmailAddress(null, 'test@example.com'), + EmailAddress(null, 'another@example.com'), + ]); + expect(result.ccMailAddresses, [ + EmailAddress(null, 'cc1@example.com'), + EmailAddress(null, 'cc2@example.com'), + ]); + expect(result.bccMailAddresses, [ + EmailAddress(null, 'bcc@example.com'), + ]); + }); + + test('should extract recipients from list post with additional parameters like cc, bcc, subject and body', () { + const listPost = ''; + + final result = EmailUtils.extractRecipientsFromListPost(listPost); + + expect(result.toMailAddresses, [EmailAddress(null, 'test@example.com')]); + expect(result.ccMailAddresses, [EmailAddress(null, 'cc@example.com')]); + expect(result.bccMailAddresses, [EmailAddress(null, 'bcc@example.com')]); + }); + }); +} diff --git a/test/features/email/parsing_email_list_post_test.dart b/test/features/email/parsing_email_list_post_test.dart deleted file mode 100644 index a0fec2b20..000000000 --- a/test/features/email/parsing_email_list_post_test.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:model/extensions/list_email_address_extension.dart'; -import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; - -void main() { - group('parsing email list post test', () { - test('parsingListPost returns null for empty input', () { - expect(EmailUtils.parsingListPost(''), isNull); - }); - - test('parsingListPost returns null for input without links', () { - expect(EmailUtils.parsingListPost('Some text without links'), isNull); - }); - - test('parsingListPost parses mailto links', () { - final listEmailAddress = - EmailUtils.parsingListPost(''); - expect(listEmailAddress, isNotNull); - expect(listEmailAddress![0].email, contains('user@example.com')); - }); - - test('parsingListPost parses both mailto without <>', () { - final listEmailAddress = - EmailUtils.parsingListPost('mailto:support@example.com'); - expect(listEmailAddress, isNotNull); - expect(listEmailAddress![0].email, contains('support@example.com')); - }); - - test('parsingListPost parses more mailto', () { - final listEmailAddress = EmailUtils.parsingListPost( - ', , '); - expect(listEmailAddress, isNotNull); - expect(listEmailAddress!.length, equals(3)); - expect( - listEmailAddress.asSetAddress(), - containsAll({ - 'support@example.com', - 'support@example2.com', - 'support@example3.com' - }), - ); - }); - - test('parsingListPost returns null for input with invalid links', () { - expect(EmailUtils.parsingListPost('Invalid link: invalid'), isNull); - }); - }); -} diff --git a/test/model/lib/extensions/presentation_email_extension_test.dart b/test/model/lib/extensions/presentation_email_extension_test.dart index 7c83980fc..f0fde8440 100644 --- a/test/model/lib/extensions/presentation_email_extension_test.dart +++ b/test/model/lib/extensions/presentation_email_extension_test.dart @@ -4,7 +4,6 @@ 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'; import 'package:model/extensions/email_address_extension.dart'; -import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart'; void main() { @@ -30,7 +29,8 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.reply, - mailboxRole: PresentationMailbox.roleSent + isSender: true, + userName: userAEmailAddress.emailAddress, ); expect(result.value1, containsAll(expectedResult.value1)); @@ -50,7 +50,8 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.replyAll, - mailboxRole: PresentationMailbox.roleSent + isSender: true, + userName: userAEmailAddress.emailAddress, ); expect(result.value1, containsAll(expectedResult.value1)); @@ -61,7 +62,7 @@ void main() { group('GIVEN user B is the sender, SENDER configured the replyTo email AND send an email to user A and user E, cc to user C, bcc to user D', () { test('THEN user A click reply, generateRecipientsEmailAddressForComposer SHOULD return only replyToEmailAddress email to reply' , () { - final expectedResult = Tuple3([replyToEmailAddress], [], []); + final expectedResult = Tuple3([userBEmailAddress], [], []); final emailToReply = PresentationEmail( from: {userBEmailAddress}, @@ -73,7 +74,7 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.reply, - mailboxRole: PresentationMailbox.roleInbox + isSender: false, ); expect(result.value1, containsAll(expectedResult.value1)); @@ -94,7 +95,7 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.replyAll, - mailboxRole: PresentationMailbox.roleInbox + isSender: false, ); expect(result.value1, containsAll(expectedResult.value1)); @@ -116,7 +117,7 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.reply, - mailboxRole: PresentationMailbox.roleInbox + isSender: false, ); expect(result.value1, containsAll(expectedResult.value1)); @@ -136,7 +137,7 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.replyAll, - mailboxRole: PresentationMailbox.roleInbox + isSender: false, ); expect(result.value1, containsAll(expectedResult.value1)); @@ -160,7 +161,7 @@ void main() { final result = emailToReplyToList.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.replyToList, - mailboxRole: PresentationMailbox.roleInbox, + isSender: false, listPost: '', ); @@ -183,7 +184,7 @@ void main() { final result = emailToReply.generateRecipientsEmailAddressForComposer( emailActionType: EmailActionType.forward, - mailboxRole: PresentationMailbox.roleInbox + isSender: false, ); expect(result.value1, containsAll(expectedResult.value1));