From 4d8c7dc52e8959b0390750bd7cce21682630e6f1 Mon Sep 17 00:00:00 2001 From: dab246 Date: Thu, 16 Nov 2023 12:40:12 +0700 Subject: [PATCH] TF-1718 Add unsubscribeMail method to datasource/repository/interactor on jmap server Signed-off-by: dab246 (cherry picked from commit f9159b651866fbe8e2a1866231b5413cecc5b597) --- .../data/datasource/email_datasource.dart | 2 ++ .../email_datasource_impl.dart | 7 ++++ .../email_hive_cache_datasource_impl.dart | 5 +++ .../email/data/network/email_api.dart | 36 +++++++++++++++++-- .../repository/email_repository_impl.dart | 5 +++ .../domain/repository/email_repository.dart | 2 ++ .../domain/state/unsubscribe_email_state.dart | 27 ++++++++++++++ .../unsubscribe_email_interactor.dart | 25 +++++++++++++ model/lib/extensions/email_id_extensions.dart | 9 +++++ .../keyword_identifier_extension.dart | 8 +++++ 10 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 lib/features/email/domain/state/unsubscribe_email_state.dart create mode 100644 lib/features/email/domain/usecases/unsubscribe_email_interactor.dart diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index e35f72c81..5b37b8e0f 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -104,4 +104,6 @@ abstract class EmailDataSource { Future> updateMultipleSendingEmail(AccountId accountId, UserName userName, List newSendingEmails); Future getStoredSendingEmail(AccountId accountId, UserName userName, String sendingId); + + Future unsubscribeMail(Session session, AccountId accountId, EmailId emailId); } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_datasource_impl.dart index de40eaccc..35feab298 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -224,4 +224,11 @@ class EmailDataSourceImpl extends EmailDataSource { Future getStoredSendingEmail(AccountId accountId, UserName userName, String sendingId) { throw UnimplementedError(); } + + @override + Future unsubscribeMail(Session session, AccountId accountId, EmailId emailId) { + return Future.sync(() async { + return await emailAPI.unsubscribeMail(session, accountId, emailId); + }).catchError(_exceptionThrower.throwException); + } } \ No newline at end of file diff --git a/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart b/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart index 2b10b9b43..709f4bb38 100644 --- a/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart @@ -287,4 +287,9 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { return sendingEmailCache.toSendingEmail(); }).catchError(_exceptionThrower.throwException); } + + @override + Future unsubscribeMail(Session session, AccountId accountId, EmailId emailId) { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index d70b16ed1..79db600cd 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -39,9 +39,11 @@ import 'package:model/account/authentication_type.dart'; import 'package:model/download/download_task_id.dart'; import 'package:model/email/attachment.dart'; import 'package:model/email/email_action_type.dart'; +import 'package:model/email/email_property.dart'; import 'package:model/email/mark_star_action.dart'; import 'package:model/email/read_actions.dart'; import 'package:model/extensions/email_extension.dart'; +import 'package:model/extensions/email_id_extensions.dart'; import 'package:model/extensions/keyword_identifier_extension.dart'; import 'package:model/extensions/list_email_extension.dart'; import 'package:model/extensions/list_email_id_extension.dart'; @@ -230,7 +232,7 @@ class EmailAPI with HandleSetErrorMixin { final getEmailMethod = GetEmailMethod(accountId) ..addIds(emails.listEmailIds.toIds().toSet()) - ..addProperties(Properties({'keywords'})); + ..addProperties(Properties({EmailProperty.keywords})); final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); @@ -438,7 +440,7 @@ class EmailAPI with HandleSetErrorMixin { final getEmailMethod = GetEmailMethod(accountId) ..addIds(emails.listEmailIds.toIds().toSet()) - ..addProperties(Properties({'keywords'})); + ..addProperties(Properties({EmailProperty.keywords})); final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); @@ -655,4 +657,34 @@ class EmailAPI with HandleSetErrorMixin { throw NotFoundEmailException(); } } + + Future unsubscribeMail(Session session, AccountId accountId, EmailId emailId) async { + final setEmailMethod = SetEmailMethod(accountId) + ..addUpdates(emailId.generateMapUpdateObjectUnsubscribeMail()); + + final getEmailMethod = GetEmailMethod(accountId) + ..addIds({emailId.id}) + ..addProperties(ThreadConstants.propertiesDefault); + + final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); + requestBuilder.invocation(setEmailMethod); + final getEmailInvocation = requestBuilder.invocation(getEmailMethod); + + final capabilities = setEmailMethod.requiredCapabilities.toCapabilitiesSupportTeamMailboxes(session, accountId); + + final response = await (requestBuilder + ..usings(capabilities)) + .build() + .execute(); + + final getEmailResponse = response.parse( + getEmailInvocation.methodCallId, + GetEmailResponse.deserialize); + + if (getEmailResponse?.list.isNotEmpty == true) { + return getEmailResponse!.list.first; + } else { + throw NotFoundEmailException(); + } + } } \ No newline at end of file diff --git a/lib/features/email/data/repository/email_repository_impl.dart b/lib/features/email/data/repository/email_repository_impl.dart index a98c51b57..3b87a7093 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -212,4 +212,9 @@ class EmailRepositoryImpl extends EmailRepository { Future transformHtmlEmailContent(String htmlContent, TransformConfiguration configuration) { return _htmlDataSource.transformHtmlEmailContent(htmlContent, configuration); } + + @override + Future unsubscribeMail(Session session, AccountId accountId, EmailId emailId) { + return emailDataSource[DataSourceType.network]!.unsubscribeMail(session, accountId, emailId); + } } \ No newline at end of file diff --git a/lib/features/email/domain/repository/email_repository.dart b/lib/features/email/domain/repository/email_repository.dart index 9f319efb9..6ec03dd12 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -104,4 +104,6 @@ abstract class EmailRepository { String htmlContent, TransformConfiguration configuration ); + + Future unsubscribeMail(Session session, AccountId accountId, EmailId emailId); } \ No newline at end of file diff --git a/lib/features/email/domain/state/unsubscribe_email_state.dart b/lib/features/email/domain/state/unsubscribe_email_state.dart new file mode 100644 index 000000000..ee4c94956 --- /dev/null +++ b/lib/features/email/domain/state/unsubscribe_email_state.dart @@ -0,0 +1,27 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; + +class UnsubscribeEmailLoading extends LoadingState {} + +class UnsubscribeEmailSuccess extends UIActionState { + final Email newEmail; + + UnsubscribeEmailSuccess( + this.newEmail, + { + jmap.State? currentEmailState, + jmap.State? currentMailboxState, + } + ) : super(currentEmailState, currentMailboxState); + + @override + List get props => [newEmail, ...super.props]; +} + +class UnsubscribeEmailFailure extends FeatureFailure { + + UnsubscribeEmailFailure({dynamic exception}) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/email/domain/usecases/unsubscribe_email_interactor.dart b/lib/features/email/domain/usecases/unsubscribe_email_interactor.dart new file mode 100644 index 000000000..cf74151d3 --- /dev/null +++ b/lib/features/email/domain/usecases/unsubscribe_email_interactor.dart @@ -0,0 +1,25 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; + +class UnsubscribeEmailInteractor { + final EmailRepository emailRepository; + + UnsubscribeEmailInteractor(this.emailRepository); + + Stream> execute(Session session, AccountId accountId, EmailId emailId) async* { + try { + yield Right(UnsubscribeEmailLoading()); + final currentEmailState = await emailRepository.getEmailState(session, accountId); + final newEmail = await emailRepository.unsubscribeMail(session, accountId, emailId); + yield Right(UnsubscribeEmailSuccess(newEmail, currentEmailState: currentEmailState)); + } catch (e) { + yield Left(UnsubscribeEmailFailure(exception: e)); + } + } +} \ No newline at end of file diff --git a/model/lib/extensions/email_id_extensions.dart b/model/lib/extensions/email_id_extensions.dart index 2841f331a..8f84ce2fb 100644 --- a/model/lib/extensions/email_id_extensions.dart +++ b/model/lib/extensions/email_id_extensions.dart @@ -1,5 +1,14 @@ +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/patch_object.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:model/extensions/keyword_identifier_extension.dart'; extension EmailIdExtension on EmailId { String get asString => id.value; + + Map generateMapUpdateObjectUnsubscribeMail() { + return { + id: KeyWordIdentifierExtension.unsubscribeMail.generateUnsubscribeActionPath() + }; + } } \ No newline at end of file diff --git a/model/lib/extensions/keyword_identifier_extension.dart b/model/lib/extensions/keyword_identifier_extension.dart index 84fb93e94..4f0bcfeec 100644 --- a/model/lib/extensions/keyword_identifier_extension.dart +++ b/model/lib/extensions/keyword_identifier_extension.dart @@ -4,6 +4,8 @@ import 'package:model/email/mark_star_action.dart'; import 'package:model/email/read_actions.dart'; extension KeyWordIdentifierExtension on KeyWordIdentifier { + static final unsubscribeMail = KeyWordIdentifier('\$unsubscribe'); + String generatePath() { return '${PatchObject.keywordsProperty}/$value'; } @@ -31,4 +33,10 @@ extension KeyWordIdentifierExtension on KeyWordIdentifier { generatePath(): true }); } + + PatchObject generateUnsubscribeActionPath() { + return PatchObject({ + generatePath(): true + }); + } } \ No newline at end of file