diff --git a/contact/pubspec.lock b/contact/pubspec.lock index b8ec281b8..7c36003e1 100644 --- a/contact/pubspec.lock +++ b/contact/pubspec.lock @@ -659,11 +659,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/contact/pubspec.yaml b/contact/pubspec.yaml index b85a3cd0f..b972b9683 100644 --- a/contact/pubspec.yaml +++ b/contact/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### equatable: 2.0.5 diff --git a/email_recovery/pubspec.lock b/email_recovery/pubspec.lock index 9977a0fb8..ae33c2ea8 100644 --- a/email_recovery/pubspec.lock +++ b/email_recovery/pubspec.lock @@ -295,11 +295,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/email_recovery/pubspec.yaml b/email_recovery/pubspec.yaml index 9ffdcbdd1..ca6816176 100644 --- a/email_recovery/pubspec.yaml +++ b/email_recovery/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### equatable: 2.0.5 diff --git a/fcm/pubspec.lock b/fcm/pubspec.lock index 92848214b..930ee9104 100644 --- a/fcm/pubspec.lock +++ b/fcm/pubspec.lock @@ -295,11 +295,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/fcm/pubspec.yaml b/fcm/pubspec.yaml index e418fae83..e2badcb37 100644 --- a/fcm/pubspec.yaml +++ b/fcm/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### equatable: 2.0.5 diff --git a/forward/pubspec.lock b/forward/pubspec.lock index 92848214b..930ee9104 100644 --- a/forward/pubspec.lock +++ b/forward/pubspec.lock @@ -295,11 +295,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/forward/pubspec.yaml b/forward/pubspec.yaml index 6af273b33..b42ce6d30 100644 --- a/forward/pubspec.yaml +++ b/forward/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### equatable: 2.0.5 diff --git a/lib/features/email/data/datasource/email_datasource.dart b/lib/features/email/data/datasource/email_datasource.dart index 54993977a..791626a6d 100644 --- a/lib/features/email/data/datasource/email_datasource.dart +++ b/lib/features/email/data/datasource/email_datasource.dart @@ -185,4 +185,6 @@ abstract class EmailDataSource { Session session, AccountId accountId, List emailIds); + + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds); } \ 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 9e9c39522..15365ac8e 100644 --- a/lib/features/email/data/datasource_impl/email_datasource_impl.dart +++ b/lib/features/email/data/datasource_impl/email_datasource_impl.dart @@ -378,4 +378,11 @@ class EmailDataSourceImpl extends EmailDataSource { Future markAsForwarded(Session session, AccountId accountId, List emailIds) { throw UnimplementedError(); } + + @override + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds) { + return Future.sync(() async { + return await emailAPI.parseEmailByBlobIds(accountId, blobIds); + }).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 46d903386..f142c9af6 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 @@ -526,4 +526,9 @@ class EmailHiveCacheDataSourceImpl extends EmailDataSource { return Future.value(); } + + @override + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds) { + 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 0fac20749..9b0d2172c 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -31,6 +31,8 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/get/get_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/get/get_email_response.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; +import 'package:jmap_dart_client/jmap/mail/email/parse/parse_email_method.dart'; +import 'package:jmap_dart_client/jmap/mail/email/parse/parse_email_response.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_response.dart'; import 'package:jmap_dart_client/jmap/mail/email/submission/address.dart'; @@ -897,4 +899,29 @@ class EmailAPI with HandleSetErrorMixin { throw SetMethodException(mapErrors); } } + + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds) async { + final requestBuilder = JmapRequestBuilder(_httpClient, ProcessingInvocation()); + final parseEmailMethod = ParseEmailMethod(accountId, blobIds); + final parseEmailInvocation = requestBuilder.invocation(parseEmailMethod); + + final response = await (requestBuilder + ..usings(parseEmailMethod.requiredCapabilities)) + .build() + .execute(); + + final parseEmailResponse = response.parse( + parseEmailInvocation.methodCallId, + ParseEmailResponse.deserialize); + + if (parseEmailResponse?.parsed?.isNotEmpty == true) { + return parseEmailResponse!.parsed!.values.toList(); + } else if (parseEmailResponse?.notParsable?.isNotEmpty == true) { + throw NotParsableBlobIdToEmailException(ids: parseEmailResponse!.notParsable!); + } else if (parseEmailResponse?.notFound?.isNotEmpty == true) { + throw NotFoundBlobIdException(parseEmailResponse!.notFound!); + } else { + throw NotParsableBlobIdToEmailException(); + } + } } \ 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 241b00188..263814227 100644 --- a/lib/features/email/data/repository/email_repository_impl.dart +++ b/lib/features/email/data/repository/email_repository_impl.dart @@ -483,4 +483,9 @@ class EmailRepositoryImpl extends EmailRepository { emailId, eventActionType); } + + @override + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds) { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/email/domain/exceptions/email_exceptions.dart b/lib/features/email/domain/exceptions/email_exceptions.dart index 8199c94c2..ffc6d02cd 100644 --- a/lib/features/email/domain/exceptions/email_exceptions.dart +++ b/lib/features/email/domain/exceptions/email_exceptions.dart @@ -1,3 +1,5 @@ +import 'package:jmap_dart_client/jmap/core/id.dart'; + class NotFoundEmailException implements Exception {} class NotFoundEmailContentException implements Exception {} @@ -8,4 +10,16 @@ class NotFoundEmailRecoveryActionException implements Exception {} class NotFoundEmailBlobIdException implements Exception {} -class CannotCreateEmailObjectException implements Exception {} \ No newline at end of file +class CannotCreateEmailObjectException implements Exception {} + +class NotFoundBlobIdException implements Exception { + final List ids; + + NotFoundBlobIdException(this.ids); +} + +class NotParsableBlobIdToEmailException implements Exception { + final List? ids; + + NotParsableBlobIdToEmailException({this.ids}); +} \ 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 d1211c6b9..1c3b4ea56 100644 --- a/lib/features/email/domain/repository/email_repository.dart +++ b/lib/features/email/domain/repository/email_repository.dart @@ -179,4 +179,6 @@ abstract class EmailRepository { AccountId accountId, EmailId emailId, EventActionType eventActionType); + + Future> parseEmailByBlobIds(AccountId accountId, Set blobIds); } \ No newline at end of file diff --git a/lib/features/email/domain/state/parse_email_by_blob_id_state.dart b/lib/features/email/domain/state/parse_email_by_blob_id_state.dart new file mode 100644 index 000000000..7f06b5bba --- /dev/null +++ b/lib/features/email/domain/state/parse_email_by_blob_id_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/mail/email/email.dart'; + +class ParsingEmailByBlobId extends LoadingState {} + +class ParseEmailByBlobIdSuccess extends UIState { + + final Email email; + + ParseEmailByBlobIdSuccess(this.email); + + @override + List get props => [email]; +} + +class ParseEmailByBlobIdFailure extends FeatureFailure { + ParseEmailByBlobIdFailure(dynamic exception) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart b/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart new file mode 100644 index 000000000..6b34755ce --- /dev/null +++ b/lib/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart @@ -0,0 +1,28 @@ +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/id.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart'; + +class ParseEmailByBlobIdInteractor { + final EmailRepository _emailRepository; + + const ParseEmailByBlobIdInteractor(this._emailRepository); + + Stream> execute(AccountId accountId, Id blobId) async* { + try { + yield Right(ParsingEmailByBlobId()); + + final emailParsed = await _emailRepository.parseEmailByBlobIds( + accountId, + {blobId}, + ); + + yield Right(ParseEmailByBlobIdSuccess(emailParsed.first)); + } catch (e) { + yield Left(ParseEmailByBlobIdFailure(e)); + } + } +} \ No newline at end of file diff --git a/model/pubspec.lock b/model/pubspec.lock index 3e1b02d95..5641e930f 100644 --- a/model/pubspec.lock +++ b/model/pubspec.lock @@ -651,11 +651,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/model/pubspec.yaml b/model/pubspec.yaml index 5c0a75a1e..d02c23c89 100644 --- a/model/pubspec.yaml +++ b/model/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### cupertino_icons: 1.0.6 diff --git a/pubspec.lock b/pubspec.lock index 4903b8ff6..0c77d0b7e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1259,11 +1259,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index defc54a36..c634fdb9e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,7 +65,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse contacts_service: git: diff --git a/rule_filter/pubspec.lock b/rule_filter/pubspec.lock index 92848214b..930ee9104 100644 --- a/rule_filter/pubspec.lock +++ b/rule_filter/pubspec.lock @@ -295,11 +295,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/rule_filter/pubspec.yaml b/rule_filter/pubspec.yaml index bb8c5c7e0..a7d755d97 100644 --- a/rule_filter/pubspec.yaml +++ b/rule_filter/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### equatable: 2.0.5 diff --git a/server_settings/pubspec.lock b/server_settings/pubspec.lock index fbf8947c3..b73c92e19 100644 --- a/server_settings/pubspec.lock +++ b/server_settings/pubspec.lock @@ -287,11 +287,11 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: bb4ffba9e3aba2cbb60c1173663abf975b521199 + ref: "feature/implement-email-parse" + resolved-ref: fbbbb2f69861719b7634b49193d9a8d2fa4e0c34 url: "https://github.com/linagora/jmap-dart-client.git" source: git - version: "0.3.0" + version: "0.3.2" js: dependency: transitive description: diff --git a/server_settings/pubspec.yaml b/server_settings/pubspec.yaml index 4e70d5572..2556e80aa 100644 --- a/server_settings/pubspec.yaml +++ b/server_settings/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: jmap_dart_client: git: url: https://github.com/linagora/jmap-dart-client.git - ref: main + ref: feature/implement-email-parse ### Dependencies from pub.dev ### equatable: 2.0.5 diff --git a/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart b/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart new file mode 100644 index 000000000..bbd44ba7c --- /dev/null +++ b/test/features/email/domain/usecases/parse_email_by_blob_id_interactor_test.dart @@ -0,0 +1,85 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart' hide State; +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/parse_email_by_blob_id_interactor.dart'; + +import '../../../../fixtures/account_fixtures.dart'; +import '../../../../fixtures/email_fixtures.dart'; + +import 'parse_email_by_blob_id_interactor_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('ParseEmailByBlobIdInteractor::execute::', () { + late MockEmailRepository mockEmailRepository; + late ParseEmailByBlobIdInteractor parseEmailByBlobIdInteractor; + + setUp(() { + mockEmailRepository = MockEmailRepository(); + parseEmailByBlobIdInteractor = + ParseEmailByBlobIdInteractor(mockEmailRepository); + }); + + final accountId = AccountFixtures.aliceAccountId; + final blobId = Id('blob-id'); + + test( + 'should emit ParsingEmailByBlobId and ParseEmailByBlobIdSuccess\n' + 'when repository call succeeds', () async { + // Arrange + final parsedEmail = EmailFixtures.email1; + + when(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + .thenAnswer((_) async => [parsedEmail]); + + // Act + final result = parseEmailByBlobIdInteractor.execute(accountId, blobId); + + // Assert + + await expectLater( + result, + emitsInOrder([ + Right(ParsingEmailByBlobId()), + Right(ParseEmailByBlobIdSuccess(parsedEmail)), + ]), + ); + + verify(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + .called(1); + verifyNoMoreInteractions(mockEmailRepository); + }); + + test( + 'should emit ParsingEmailByBlobId and ParseEmailByBlobIdFailure\n' + 'when repository call throws exception', () async { + // Arrange + final exception = Exception('Failed to parse email'); + + when(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + .thenThrow(exception); + + // Act + final result = parseEmailByBlobIdInteractor.execute(accountId, blobId); + + // Assert + await expectLater( + result, + emitsInOrder([ + Right(ParsingEmailByBlobId()), + Left(ParseEmailByBlobIdFailure(exception)), + ]), + ); + + verify(mockEmailRepository.parseEmailByBlobIds(accountId, {blobId})) + .called(1); + verifyNoMoreInteractions(mockEmailRepository); + }); + }); +}