TF-1718 Check List-Unsubscribe in header of email & parsing to EmailUnsubscribe
(cherry picked from commit 9dc046a951e5198461178860c8ebe4bedff9062f)
This commit is contained in:
@@ -58,6 +58,8 @@ import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_
|
|||||||
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/usecases/send_receipt_to_sender_interactor.dart';
|
import 'package:tmail_ui_user/features/email/domain/usecases/send_receipt_to_sender_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_bottom_sheet_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_bottom_sheet_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
|
||||||
@@ -113,6 +115,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
final calendarEvent = Rxn<CalendarEvent>();
|
final calendarEvent = Rxn<CalendarEvent>();
|
||||||
final eventActions = <EventAction>[].obs;
|
final eventActions = <EventAction>[].obs;
|
||||||
final emailLoadedViewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
|
final emailLoadedViewState = Rx<Either<Failure, Success>>(Right(UIState.idle));
|
||||||
|
final emailUnsubscribe = Rxn<EmailUnsubscribe>();
|
||||||
|
|
||||||
EmailId? _currentEmailId;
|
EmailId? _currentEmailId;
|
||||||
Identity? _identitySelected;
|
Identity? _identitySelected;
|
||||||
@@ -472,8 +475,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
emailId: currentEmail!.id!,
|
emailId: currentEmail!.id!,
|
||||||
createdTime: currentEmail?.receivedAt?.value ?? DateTime.now(),
|
createdTime: currentEmail?.receivedAt?.value ?? DateTime.now(),
|
||||||
attachments: success.attachments,
|
attachments: success.attachments,
|
||||||
headers: currentEmail?.emailHeader?.toSet(),
|
headers: success.emailCurrent?.headers,
|
||||||
keywords: currentEmail?.keywords,
|
keywords: success.emailCurrent?.keywords,
|
||||||
htmlEmailContent: success.htmlEmailContent,
|
htmlEmailContent: success.htmlEmailContent,
|
||||||
messageId: success.emailCurrent?.messageId,
|
messageId: success.emailCurrent?.messageId,
|
||||||
references: success.emailCurrent?.references,
|
references: success.emailCurrent?.references,
|
||||||
@@ -491,9 +494,19 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
if (isShowMessageReadReceipt) {
|
if (isShowMessageReadReceipt) {
|
||||||
_handleReadReceipt();
|
_handleReadReceipt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (success.emailCurrent?.hasListUnsubscribe == true) {
|
||||||
|
_handleUnsubscribe(success.emailCurrent!.listUnsubscribe);
|
||||||
|
} else {
|
||||||
|
emailUnsubscribe.value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleUnsubscribe(String listUnsubscribe) {
|
||||||
|
emailUnsubscribe.value = EmailUtils.parsingUnsubscribe(listUnsubscribe);
|
||||||
|
}
|
||||||
|
|
||||||
void _handleReadReceipt() {
|
void _handleReadReceipt() {
|
||||||
if (currentContext != null) {
|
if (currentContext != null) {
|
||||||
showConfirmDialogAction(currentContext!,
|
showConfirmDialogAction(currentContext!,
|
||||||
@@ -514,6 +527,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
attachments.clear();
|
attachments.clear();
|
||||||
calendarEvent.value = null;
|
calendarEvent.value = null;
|
||||||
eventActions.clear();
|
eventActions.clear();
|
||||||
|
emailUnsubscribe.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
PresentationMailbox? getMailboxContain(PresentationEmail email) {
|
PresentationMailbox? getMailboxContain(PresentationEmail email) {
|
||||||
|
|||||||
@@ -298,12 +298,13 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
EmailSubjectWidget(presentationEmail: presentationEmail),
|
EmailSubjectWidget(presentationEmail: presentationEmail),
|
||||||
InformationSenderAndReceiverBuilder(
|
Obx(() => InformationSenderAndReceiverBuilder(
|
||||||
controller: controller,
|
|
||||||
emailSelected: presentationEmail,
|
emailSelected: presentationEmail,
|
||||||
imagePaths: controller.imagePaths,
|
imagePaths: controller.imagePaths,
|
||||||
responsiveUtils: controller.responsiveUtils,
|
responsiveUtils: controller.responsiveUtils,
|
||||||
),
|
emailUnsubscribe: controller.emailUnsubscribe.value,
|
||||||
|
openEmailAddressDetailAction: controller.openEmailAddressDialog,
|
||||||
|
)),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final attachments = controller.attachments.listAttachmentsDisplayedOutSide;
|
final attachments = controller.attachments.listAttachmentsDisplayedOutSide;
|
||||||
if (attachments.isNotEmpty) {
|
if (attachments.isNotEmpty) {
|
||||||
@@ -429,7 +430,8 @@ class EmailView extends GetWidget<SingleEmailController> {
|
|||||||
EmailActionType.moveToSpam,
|
EmailActionType.moveToSpam,
|
||||||
if (presentationEmail.from?.isNotEmpty == true)
|
if (presentationEmail.from?.isNotEmpty == true)
|
||||||
EmailActionType.createRule,
|
EmailActionType.createRule,
|
||||||
EmailActionType.unsubscribe
|
if (controller.emailUnsubscribe.value != null)
|
||||||
|
EmailActionType.unsubscribe
|
||||||
];
|
];
|
||||||
|
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
class EmailUnsubscribe with EquatableMixin {
|
||||||
|
|
||||||
|
final List<String> httpLinks;
|
||||||
|
final List<String> mailtoLinks;
|
||||||
|
|
||||||
|
EmailUnsubscribe({
|
||||||
|
required this.httpLinks,
|
||||||
|
required this.mailtoLinks
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
httpLinks,
|
||||||
|
mailtoLinks
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
|
||||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||||
|
|
||||||
@@ -15,4 +18,35 @@ class EmailUtils {
|
|||||||
return ThreadConstants.propertiesDefault;
|
return ThreadConstants.propertiesDefault;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EmailUnsubscribe? parsingUnsubscribe(String listUnsubscribe) {
|
||||||
|
if (listUnsubscribe.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final regExpMailtoLinks = RegExp(r'mailto:([^>,]*)');
|
||||||
|
final allMatchesMailtoLinks = regExpMailtoLinks.allMatches(listUnsubscribe);
|
||||||
|
final listMailtoLinks = allMatchesMailtoLinks
|
||||||
|
.map((match) => match.group(0))
|
||||||
|
.whereNotNull()
|
||||||
|
.toList();
|
||||||
|
log('EmailUtils::parsingUnsubscribe:listMailtoLinks: $listMailtoLinks');
|
||||||
|
|
||||||
|
final regExpHttpLinks = RegExp(r'http([^>,]*)');
|
||||||
|
final allMatchesHttpLinks = regExpHttpLinks.allMatches(listUnsubscribe);
|
||||||
|
final listHttpLinks = allMatchesHttpLinks
|
||||||
|
.map((match) => match.group(0))
|
||||||
|
.whereNotNull()
|
||||||
|
.toList();
|
||||||
|
log('EmailUtils::parsingUnsubscribe:listHttpLinks: $listHttpLinks');
|
||||||
|
|
||||||
|
if (listMailtoLinks.isNotEmpty || listHttpLinks.isNotEmpty) {
|
||||||
|
return EmailUnsubscribe(
|
||||||
|
httpLinks: listHttpLinks,
|
||||||
|
mailtoLinks: listMailtoLinks
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,22 +15,21 @@ import 'package:model/extensions/list_email_address_extension.dart';
|
|||||||
import 'package:model/extensions/presentation_email_extension.dart';
|
import 'package:model/extensions/presentation_email_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/material_text_button.dart';
|
import 'package:tmail_ui_user/features/base/widget/material_text_button.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_sender_builder.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||||
|
|
||||||
typedef OnPreviewEmailAddressActionCallback = Function(BuildContext context, EmailAddress emailAddress);
|
|
||||||
|
|
||||||
class EmailReceiverWidget extends StatefulWidget {
|
class EmailReceiverWidget extends StatefulWidget {
|
||||||
|
|
||||||
final PresentationEmail emailSelected;
|
final PresentationEmail emailSelected;
|
||||||
final double maxWidth;
|
final double maxWidth;
|
||||||
final OnPreviewEmailAddressActionCallback? onPreviewEmailAddressActionCallback;
|
final OnOpenEmailAddressDetailAction? openEmailAddressDetailAction;
|
||||||
|
|
||||||
const EmailReceiverWidget({
|
const EmailReceiverWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.emailSelected,
|
required this.emailSelected,
|
||||||
this.maxWidth = 200,
|
this.maxWidth = 200,
|
||||||
this.onPreviewEmailAddressActionCallback,
|
this.openEmailAddressDetailAction,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -218,7 +217,7 @@ class _EmailReceiverWidgetState extends State<EmailReceiverWidget> {
|
|||||||
label: lastEmailAddress == emailAddress
|
label: lastEmailAddress == emailAddress
|
||||||
? emailAddress.asString()
|
? emailAddress.asString()
|
||||||
: '${emailAddress.asString()},',
|
: '${emailAddress.asString()},',
|
||||||
onTap: () => widget.onPreviewEmailAddressActionCallback?.call(context, emailAddress),
|
onTap: () => widget.openEmailAddressDetailAction?.call(context, emailAddress),
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
AppUtils.copyEmailAddressToClipboard(context, emailAddress.emailAddress);
|
AppUtils.copyEmailAddressToClipboard(context, emailAddress.emailAddress);
|
||||||
},
|
},
|
||||||
|
|||||||
+9
-7
@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:model/email/presentation_email.dart';
|
import 'package:model/email/presentation_email.dart';
|
||||||
import 'package:model/extensions/presentation_email_extension.dart';
|
import 'package:model/extensions/presentation_email_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/email_avatar_builder.dart';
|
import 'package:tmail_ui_user/features/base/widget/email_avatar_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_receiver_widget.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_receiver_widget.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_sender_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_sender_builder.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/received_time_builder.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/received_time_builder.dart';
|
||||||
@@ -14,17 +14,19 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
|||||||
|
|
||||||
class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
||||||
|
|
||||||
final SingleEmailController controller;
|
|
||||||
final PresentationEmail emailSelected;
|
final PresentationEmail emailSelected;
|
||||||
final ResponsiveUtils responsiveUtils;
|
final ResponsiveUtils responsiveUtils;
|
||||||
final ImagePaths imagePaths;
|
final ImagePaths imagePaths;
|
||||||
|
final EmailUnsubscribe? emailUnsubscribe;
|
||||||
|
final OnOpenEmailAddressDetailAction? openEmailAddressDetailAction;
|
||||||
|
|
||||||
const InformationSenderAndReceiverBuilder({
|
const InformationSenderAndReceiverBuilder({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.controller,
|
|
||||||
required this.emailSelected,
|
required this.emailSelected,
|
||||||
required this.responsiveUtils,
|
required this.responsiveUtils,
|
||||||
required this.imagePaths
|
required this.imagePaths,
|
||||||
|
required this.emailUnsubscribe,
|
||||||
|
this.openEmailAddressDetailAction,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -54,10 +56,10 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
|||||||
transform: Matrix4.translationValues(-5.0, 0.0, 0.0),
|
transform: Matrix4.translationValues(-5.0, 0.0, 0.0),
|
||||||
child: EmailSenderBuilder(
|
child: EmailSenderBuilder(
|
||||||
emailAddress: emailSelected.from!.first,
|
emailAddress: emailSelected.from!.first,
|
||||||
openEmailAddressDetailAction: controller.openEmailAddressDialog,
|
openEmailAddressDetailAction: openEmailAddressDetailAction,
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
if (!responsiveUtils.isPortraitMobile(context))
|
if (emailUnsubscribe != null && !responsiveUtils.isPortraitMobile(context))
|
||||||
TMailButtonWidget.fromText(
|
TMailButtonWidget.fromText(
|
||||||
text: AppLocalizations.of(context).unsubscribe,
|
text: AppLocalizations.of(context).unsubscribe,
|
||||||
textStyle: const TextStyle(
|
textStyle: const TextStyle(
|
||||||
@@ -81,7 +83,7 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget {
|
|||||||
EmailReceiverWidget(
|
EmailReceiverWidget(
|
||||||
emailSelected: emailSelected,
|
emailSelected: emailSelected,
|
||||||
maxWidth: constraints.maxWidth,
|
maxWidth: constraints.maxWidth,
|
||||||
onPreviewEmailAddressActionCallback: controller.openEmailAddressDialog,
|
openEmailAddressDetailAction: openEmailAddressDetailAction,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:core/utils/app_logger.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
||||||
import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart';
|
import 'package:jmap_dart_client/jmap/mail/email/email_body_part.dart';
|
||||||
@@ -11,6 +13,8 @@ import 'package:model/model.dart';
|
|||||||
|
|
||||||
extension EmailExtension on Email {
|
extension EmailExtension on Email {
|
||||||
|
|
||||||
|
static const String unsubscribeHeaderName = 'List-Unsubscribe';
|
||||||
|
|
||||||
String asString() => jsonEncode(toJson());
|
String asString() => jsonEncode(toJson());
|
||||||
|
|
||||||
bool get hasRead => keywords?.containsKey(KeyWordIdentifier.emailSeen) == true;
|
bool get hasRead => keywords?.containsKey(KeyWordIdentifier.emailSeen) == true;
|
||||||
@@ -23,6 +27,14 @@ extension EmailExtension on Email {
|
|||||||
|
|
||||||
bool get withAttachments => hasAttachment == true;
|
bool get withAttachments => hasAttachment == true;
|
||||||
|
|
||||||
|
String get listUnsubscribe {
|
||||||
|
final listUnsubscribe = headers?.firstWhereOrNull((header) => header.name == unsubscribeHeaderName);
|
||||||
|
log('EmailExtension::listUnsubscribe: $listUnsubscribe');
|
||||||
|
return listUnsubscribe?.value ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasListUnsubscribe => listUnsubscribe.isNotEmpty;
|
||||||
|
|
||||||
bool hasReadReceipt(Map<MailboxId, PresentationMailbox> mapMailbox) {
|
bool hasReadReceipt(Map<MailboxId, PresentationMailbox> mapMailbox) {
|
||||||
final mailboxCurrent = findMailboxContain(mapMailbox);
|
final mailboxCurrent = findMailboxContain(mapMailbox);
|
||||||
return !hasMdnSent &&
|
return !hasMdnSent &&
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('parsing email unsubscribe test', () {
|
||||||
|
test('parsingUnsubscribe returns null for empty input', () {
|
||||||
|
expect(EmailUtils.parsingUnsubscribe(''), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe returns null for input without links', () {
|
||||||
|
expect(EmailUtils.parsingUnsubscribe('Some text without links'), isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses mailto links', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('<mailto:user@example.com>');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.mailtoLinks, contains('mailto:user@example.com'));
|
||||||
|
expect(emailUnsubscribe.httpLinks, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses http links', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('<http://example.com>');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.httpLinks, contains('http://example.com'));
|
||||||
|
expect(emailUnsubscribe.mailtoLinks, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses https links', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('<https://example.com>');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.httpLinks, contains('https://example.com'));
|
||||||
|
expect(emailUnsubscribe.mailtoLinks, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses both http and https links', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('<http://example.com>, <https://example.com>');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.httpLinks, containsAll(['http://example.com', 'https://example.com']));
|
||||||
|
expect(emailUnsubscribe.mailtoLinks, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses both mailto and http links', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('<mailto:support@example.com>, <http://example.com>');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.mailtoLinks, contains('mailto:support@example.com'));
|
||||||
|
expect(emailUnsubscribe.httpLinks, contains('http://example.com'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses both mailto and http links without <>', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('mailto:support@example.com, http://example.com');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.mailtoLinks, contains('mailto:support@example.com'));
|
||||||
|
expect(emailUnsubscribe.httpLinks, contains('http://example.com'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe parses more mailto and http links', () {
|
||||||
|
final emailUnsubscribe = EmailUtils.parsingUnsubscribe('<mailto:support@example.com>, <http://example.com>, <http://example2.com>, <http://example3.com>, <mailto:support@example2.com>, <mailto:support@example3.com>');
|
||||||
|
expect(emailUnsubscribe, isNotNull);
|
||||||
|
expect(emailUnsubscribe!.mailtoLinks, containsAll(['mailto:support@example.com', 'mailto:support@example2.com', 'mailto:support@example3.com']));
|
||||||
|
expect(emailUnsubscribe.httpLinks, containsAll(['http://example.com', 'http://example2.com', 'http://example3.com']));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parsingUnsubscribe returns null for input with invalid links', () {
|
||||||
|
expect(EmailUtils.parsingUnsubscribe('Invalid link: invalid'), isNull);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user