diff --git a/lib/features/mailbox/data/datasource/mailbox_datasource.dart b/lib/features/mailbox/data/datasource/mailbox_datasource.dart index 21bbd0375..c50321e47 100644 --- a/lib/features/mailbox/data/datasource/mailbox_datasource.dart +++ b/lib/features/mailbox/data/datasource/mailbox_datasource.dart @@ -9,6 +9,7 @@ import 'package:jmap_dart_client/jmap/core/id.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/state.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; @@ -59,4 +60,6 @@ abstract class MailboxDataSource { Future getMailboxByRole(Session session, AccountId accountId, Role role); Future clearAllMailboxCache(AccountId accountId, UserName userName); + + Future clearMailbox(Session session, AccountId accountId, MailboxId mailboxId); } \ No newline at end of file diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart index 3f72ea621..65eb4d641 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_cache_datasource_impl.dart @@ -161,4 +161,9 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource { return await _mailboxCacheManager.clearAll(accountId, userName); }).catchError(_exceptionThrower.throwException); } + + @override + Future clearMailbox(Session session, AccountId accountId, MailboxId mailboxId) { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart index 4b9760ae0..23a3495c2 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart @@ -154,4 +154,11 @@ class MailboxDataSourceImpl extends MailboxDataSource { Future clearAllMailboxCache(AccountId accountId, UserName userName) { throw UnimplementedError(); } + + @override + Future clearMailbox(Session session, AccountId accountId, MailboxId mailboxId) { + return Future.sync(() async { + return await mailboxAPI.clearMailbox(session, accountId, mailboxId); + }).catchError(_exceptionThrower.throwException); + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/network/mailbox_api.dart b/lib/features/mailbox/data/network/mailbox_api.dart index f9ff8027a..76d7c0cc8 100644 --- a/lib/features/mailbox/data/network/mailbox_api.dart +++ b/lib/features/mailbox/data/network/mailbox_api.dart @@ -20,6 +20,8 @@ import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/changes/changes_mailbox_method.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/changes/changes_mailbox_response.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/clear/clear_mailbox_method.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/clear/clear_mailbox_response.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_method.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; @@ -607,4 +609,32 @@ class MailboxAPI with HandleSetErrorMixin { throw NotFoundMailboxException(); } } + + Future clearMailbox( + Session session, + AccountId accountId, + MailboxId mailboxId, + ) async { + final clearMailboxMethod = ClearMailboxMethod(accountId, mailboxId); + final requestBuilder = JmapRequestBuilder(httpClient, ProcessingInvocation()); + final invocation = requestBuilder.invocation(clearMailboxMethod); + + final response = await (requestBuilder + ..usings(clearMailboxMethod.requiredCapabilities)) + .build() + .execute(); + + final clearMailboxResponse = response.parse( + invocation.methodCallId, + ClearMailboxResponse.deserialize, + ); + + if (clearMailboxResponse?.totalDeletedMessagesCount != null) { + return clearMailboxResponse!.totalDeletedMessagesCount!; + } else if (clearMailboxResponse?.notCleared != null) { + throw clearMailboxResponse!.notCleared!; + } else { + throw NotFoundClearMailboxResponseException(); + } + } } \ No newline at end of file diff --git a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart index b4e8e3273..f2fd114e3 100644 --- a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart +++ b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart @@ -300,4 +300,9 @@ class MailboxRepositoryImpl extends MailboxRepository { Future getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}) { return mapDataSource[DataSourceType.network]!.getMailboxByRole(session, accountId, role); } + + @override + Future clearMailbox(Session session, AccountId accountId, MailboxId mailboxId) { + return mapDataSource[DataSourceType.network]!.clearMailbox(session, accountId, mailboxId); + } } \ No newline at end of file diff --git a/lib/features/mailbox/domain/exceptions/mailbox_exception.dart b/lib/features/mailbox/domain/exceptions/mailbox_exception.dart index bc474e117..68c8ace28 100644 --- a/lib/features/mailbox/domain/exceptions/mailbox_exception.dart +++ b/lib/features/mailbox/domain/exceptions/mailbox_exception.dart @@ -2,3 +2,5 @@ class NotFoundInboxMailboxException implements Exception {} class NotFoundMailboxException implements Exception {} + +class NotFoundClearMailboxResponseException implements Exception {} diff --git a/lib/features/mailbox/domain/repository/mailbox_repository.dart b/lib/features/mailbox/domain/repository/mailbox_repository.dart index 07ad05044..4504c5fad 100644 --- a/lib/features/mailbox/domain/repository/mailbox_repository.dart +++ b/lib/features/mailbox/domain/repository/mailbox_repository.dart @@ -54,4 +54,6 @@ abstract class MailboxRepository { Future<(List mailboxes, Map mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox); Future getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}); + + Future clearMailbox(Session session, AccountId accountId, MailboxId mailboxId); } \ No newline at end of file diff --git a/lib/features/mailbox/domain/state/clear_mailbox_state.dart b/lib/features/mailbox/domain/state/clear_mailbox_state.dart new file mode 100644 index 000000000..91954c3c4 --- /dev/null +++ b/lib/features/mailbox/domain/state/clear_mailbox_state.dart @@ -0,0 +1,19 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; + +class ClearingMailbox extends LoadingState {} + +class ClearMailboxSuccess extends UIState { + final UnsignedInt totalDeletedMessages; + + ClearMailboxSuccess(this.totalDeletedMessages); + + @override + List get props => [totalDeletedMessages]; +} + +class ClearMailboxFailure extends FeatureFailure { + + ClearMailboxFailure(dynamic exception) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/mailbox/domain/usecases/clear_mailbox_interactor.dart b/lib/features/mailbox/domain/usecases/clear_mailbox_interactor.dart new file mode 100644 index 000000000..3a14e7042 --- /dev/null +++ b/lib/features/mailbox/domain/usecases/clear_mailbox_interactor.dart @@ -0,0 +1,32 @@ +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/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.dart'; + +class ClearMailboxInteractor { + final MailboxRepository _mailboxRepository; + + ClearMailboxInteractor(this._mailboxRepository); + + Stream> execute( + Session session, + AccountId accountId, + MailboxId mailboxId, + ) async* { + try { + yield Right(ClearingMailbox()); + final totalDeletedMessages = await _mailboxRepository.clearMailbox( + session, + accountId, + mailboxId, + ); + yield Right(ClearMailboxSuccess(totalDeletedMessages)); + } catch (e) { + yield Left(ClearMailboxFailure(e)); + } + } +} diff --git a/test/features/mailbox/data/mailbox_api_test.dart b/test/features/mailbox/data/mailbox_api_test.dart index 4b7264412..a196edb7d 100644 --- a/test/features/mailbox/data/mailbox_api_test.dart +++ b/test/features/mailbox/data/mailbox_api_test.dart @@ -1,5 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:jmap_dart_client/http/http_client.dart'; +import 'package:jmap_dart_client/jmap/core/error/set_error.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:mockito/annotations.dart'; @@ -389,5 +390,89 @@ void main() { ); }); }); + + group('clearMailbox method test', () { + final trashMailboxId = MailboxId(Id('trash-id')); + final notFoundMailboxId = MailboxId(Id('notFoundMailboxId')); + + test('Should return totalDeletedMessagesCount when clear mailbox success', () async { + final mapResponseData = { + "methodResponses": [ + [ + "Mailbox/clear", + { + "accountId": accountId.asString, + "totalDeletedMessagesCount": 10, + }, + "c0" + ] + ], + "sessionState": "0" + }; + + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenAnswer((_) async => mapResponseData); + + final result = await mailboxAPI.clearMailbox( + session, + accountId, + trashMailboxId, + ); + + verify(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )); + + expect(result.value, 10); + }); + + test('Should return notCleared when clear mailbox fail with mailbox id not found', () async { + final mapResponseData = { + "methodResponses": [ + [ + "Mailbox/clear", + { + "accountId": accountId.asString, + "notCleared": { + "type": "notFound", + "description": "${notFoundMailboxId.id.value} can not be found" + } + }, + "c0" + ] + ], + "sessionState": "0" + }; + + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenAnswer((_) async => mapResponseData); + + expect( + () => mailboxAPI.clearMailbox(session, accountId, notFoundMailboxId), + throwsA(isA()), + ); + }); + + test('Should throw exception when http client throw exception', () async { + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenThrow(Exception()); + + expect( + () => mailboxAPI.clearMailbox(session, accountId, trashMailboxId), + throwsA(isA()), + ); + }); + }); }); }