diff --git a/lib/features/mailbox/data/datasource/mailbox_datasource.dart b/lib/features/mailbox/data/datasource/mailbox_datasource.dart index aa553bca6..21bbd0375 100644 --- a/lib/features/mailbox/data/datasource/mailbox_datasource.dart +++ b/lib/features/mailbox/data/datasource/mailbox_datasource.dart @@ -52,7 +52,7 @@ abstract class MailboxDataSource { Future handleMailboxRightRequest(Session session, AccountId accountId, MailboxRightRequest request); - Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List listRole); + Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, Map mapRoles); Future<(List mailboxes, Map mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox); 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 12d7f8933..3f72ea621 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 @@ -141,7 +141,7 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource { } @override - Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List listRole) { + Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, Map mapRoles) { throw UnimplementedError(); } 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 e616c445c..4b9760ae0 100644 --- a/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart +++ b/lib/features/mailbox/data/datasource_impl/mailbox_datasource_impl.dart @@ -130,9 +130,9 @@ class MailboxDataSourceImpl extends MailboxDataSource { } @override - Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List listRole) { + Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, Map mapRoles) { return Future.sync(() async { - return await mailboxAPI.createDefaultMailbox(session, accountId, listRole); + return await mailboxAPI.createDefaultMailbox(session, accountId, mapRoles); }).catchError(_exceptionThrower.throwException); } diff --git a/lib/features/mailbox/data/network/mailbox_api.dart b/lib/features/mailbox/data/network/mailbox_api.dart index 0ee986197..f9ff8027a 100644 --- a/lib/features/mailbox/data/network/mailbox_api.dart +++ b/lib/features/mailbox/data/network/mailbox_api.dart @@ -456,13 +456,8 @@ class MailboxAPI with HandleSetErrorMixin { Future<(List mailboxes, Map mapErrors)> createDefaultMailbox( Session session, AccountId accountId, - List listRole + Map mapRoles, ) async { - final mapRoles = { - for (var role in listRole) - Id(_uuid.v1()) : role - }; - final mapCreate = { for (var id in mapRoles.keys) id : Mailbox(name: MailboxName(mapRoles[id]!.mailboxName), isSubscribed: IsSubscribed(true)) diff --git a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart index 38db39162..f00f13a5b 100644 --- a/lib/features/mailbox/data/repository/mailbox_repository_impl.dart +++ b/lib/features/mailbox/data/repository/mailbox_repository_impl.dart @@ -292,8 +292,8 @@ class MailboxRepositoryImpl extends MailboxRepository { } @override - Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List listRole) { - return mapDataSource[DataSourceType.network]!.createDefaultMailbox(session, accountId, listRole); + Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, Map mapRoles) { + return mapDataSource[DataSourceType.network]!.createDefaultMailbox(session, accountId, mapRoles); } @override diff --git a/lib/features/mailbox/domain/repository/mailbox_repository.dart b/lib/features/mailbox/domain/repository/mailbox_repository.dart index 1a22deed7..07ad05044 100644 --- a/lib/features/mailbox/domain/repository/mailbox_repository.dart +++ b/lib/features/mailbox/domain/repository/mailbox_repository.dart @@ -49,7 +49,7 @@ abstract class MailboxRepository { Future handleMailboxRightRequest(Session session, AccountId accountId, MailboxRightRequest request); - Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List listRole); + Future<(List mailboxes, Map mapErrors)> createDefaultMailbox(Session session, AccountId accountId, Map mapRoles); Future<(List mailboxes, Map mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List listMailbox); diff --git a/lib/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart b/lib/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart index 3c2a1d785..c6cf11fe9 100644 --- a/lib/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart +++ b/lib/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart @@ -3,6 +3,7 @@ import 'package:core/presentation/state/success.dart'; import 'package:core/utils/app_logger.dart'; import 'package:dartz/dartz.dart' as dartz; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/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/exceptions/set_mailbox_method_exception.dart'; @@ -17,14 +18,14 @@ class CreateDefaultMailboxInteractor { Stream> execute( Session session, AccountId accountId, - List listRole + Map mapRoles, ) async* { try { yield dartz.Right(CreateDefaultMailboxLoading()); final mailboxesRecord = await _mailboxRepository.createDefaultMailbox( session, accountId, - listRole + mapRoles, ); final listMailboxCreated = mailboxesRecord.$1; diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index 0fc64917b..d9db0061a 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -10,6 +10,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/error/method/error_method_response.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; @@ -650,12 +651,17 @@ class MailboxController extends BaseMailboxController final listRoleMissing = MailboxConstants.defaultMailboxRoles .whereNot((role) => mapDefaultMailboxRole.containsKey(role) || findNodeByNameOnFirstLevel(role.value) != null) .toList(); - log('MailboxController::_handleCreateDefaultFolderIfMissing():listRoleMissing: $listRoleMissing'); - if (listRoleMissing.isNotEmpty && accountId != null && session != null) { + + final mapRoles = { + for (var role in listRoleMissing) + Id(uuid.v1()) : role + }; + log('MailboxController::_handleCreateDefaultFolderIfMissing():mapRoles: $mapRoles'); + if (mapRoles.isNotEmpty && accountId != null && session != null) { consumeState(_createDefaultMailboxInteractor.execute( session!, accountId!, - listRoleMissing + mapRoles, )); } } diff --git a/test/features/mailbox/data/mailbox_api_test.dart b/test/features/mailbox/data/mailbox_api_test.dart new file mode 100644 index 000000000..4b7264412 --- /dev/null +++ b/test/features/mailbox/data/mailbox_api_test.dart @@ -0,0 +1,393 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:jmap_dart_client/http/http_client.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'; +import 'package:mockito/mockito.dart'; +import 'package:model/extensions/account_id_extensions.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/extensions/role_extension.dart'; +import 'package:uuid/uuid.dart'; + +import '../../../fixtures/account_fixtures.dart'; +import '../../../fixtures/session_fixtures.dart'; + +import 'mailbox_api_test.mocks.dart'; + +@GenerateNiceMocks([ + MockSpec(), + MockSpec() +]) +void main() { + group('MailboxAPI::', () { + late HttpClient httpClient; + late Uuid uuid; + late MailboxAPI mailboxAPI; + + final accountId = AccountFixtures.aliceAccountId; + final session = SessionFixtures.aliceSession; + + final mapRoles = { + Id('sent-create-id'): PresentationMailbox.roleSent, + Id('outbox-create-id'): PresentationMailbox.roleOutbox, + }; + + setUp(() { + httpClient = MockHttpClient(); + uuid = MockUuid(); + + mailboxAPI = MailboxAPI(httpClient, uuid); + }); + + group('createDefaultMailbox::', () { + test('Should return full mailbox with input is a list roles when create mailbox success', () async { + final mapResponseData = { + "methodResponses": [ + [ + "Mailbox/set", + { + "oldState": "105", + "newState": "107", + "created": { + "sent-create-id": { + "id": "sent-id", + "myRights": { + "mayReadItems": true, + "mayAddItems": true, + "mayRemoveItems": true, + "mayCreateChild": true, + "mayDelete": true, + "maySubmit": true, + "maySetSeen": true, + "maySetKeywords": true, + "mayAdmin": true, + "mayRename": true + }, + "totalEmails": 0, + "unreadEmails": 0, + "totalThreads": 0, + "unreadThreads": 0, + "isSeenShared": false, + "sortOrder": 10, + "showAsLabel": true + }, + "outbox-create-id": { + "id": "outbox-id", + "myRights": { + "mayReadItems": true, + "mayAddItems": true, + "mayRemoveItems": true, + "mayCreateChild": true, + "mayDelete": true, + "maySubmit": true, + "maySetSeen": true, + "maySetKeywords": true, + "mayAdmin": true, + "mayRename": true + }, + "totalEmails": 0, + "unreadEmails": 0, + "totalThreads": 0, + "unreadThreads": 0, + "isSeenShared": false, + "sortOrder": 10, + "showAsLabel": true + } + }, + "updated": null, + "destroyed": null, + "notCreated": null, + "notUpdated": null, + "notDestroyed": null, + "accountId": accountId.asString, + }, + "c0" + ] + ], + "sessionState": "0" + }; + + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenAnswer((_) async => mapResponseData); + + final mailboxRecords = await mailboxAPI.createDefaultMailbox( + session, + accountId, + mapRoles, + ); + + final listMailbox = mailboxRecords.$1; + final mapErrors = mailboxRecords.$2; + + verify(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )); + expect(listMailbox.length, mapRoles.length); + expect(mapErrors.isEmpty, isTrue); + expect( + listMailbox.any((mailbox) => mailbox.name!.name == PresentationMailbox.roleSent.mailboxName), + isTrue, + ); + expect( + listMailbox.any((mailbox) => mailbox.name!.name == PresentationMailbox.roleOutbox.mailboxName), + isTrue, + ); + }); + + test('Should return some mailbox list with input is a list roles when create mailbox fail', () async { + final mapResponseData = { + "methodResponses": [ + [ + "Mailbox/set", + { + "oldState": "105", + "newState": "107", + "created": { + "sent-create-id": { + "id": "sent-id", + "myRights": { + "mayReadItems": true, + "mayAddItems": true, + "mayRemoveItems": true, + "mayCreateChild": true, + "mayDelete": true, + "maySubmit": true, + "maySetSeen": true, + "maySetKeywords": true, + "mayAdmin": true, + "mayRename": true + }, + "totalEmails": 0, + "unreadEmails": 0, + "totalThreads": 0, + "unreadThreads": 0, + "isSeenShared": false, + "sortOrder": 10, + "showAsLabel": true + } + }, + "updated": null, + "destroyed": null, + "notCreated": { + "outbox-create-id": { + "type": "invalidProperties", + "properties": [ + "role" + ] + } + }, + "notUpdated": null, + "notDestroyed": null, + "accountId": accountId.asString, + }, + "c0" + ] + ], + "sessionState": "0" + }; + + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenAnswer((_) async => mapResponseData); + + final mailboxRecords = await mailboxAPI.createDefaultMailbox( + session, + accountId, + mapRoles, + ); + + final listMailbox = mailboxRecords.$1; + final mapErrors = mailboxRecords.$2; + + verify(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )); + + expect(listMailbox.length, lessThan(mapRoles.length)); + expect(mapErrors.isNotEmpty, isTrue); + expect( + listMailbox.any((mailbox) => mailbox.name?.name == PresentationMailbox.roleSent.mailboxName), + isTrue, + ); + expect( + listMailbox.every((mailbox) => mailbox.name?.name != PresentationMailbox.roleOutbox.mailboxName), + isTrue, + ); + }); + + test('Should throw exception when http client throw exception', () async { + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenThrow(Exception()); + + expect( + () => mailboxAPI.createDefaultMailbox(session, accountId, mapRoles), + throwsA(isA()), + ); + }); + }); + + group('setRoleDefaultMailbox::', () { + final listMailbox = [ + Mailbox( + id: MailboxId(Id('sent-id')), + name: MailboxName(PresentationMailbox.roleSent.mailboxName), + role: PresentationMailbox.roleSent, + isSubscribed: IsSubscribed(true), + ) , + Mailbox( + id: MailboxId(Id('outbox-id')), + name: MailboxName(PresentationMailbox.roleOutbox.mailboxName), + role: PresentationMailbox.roleOutbox, + isSubscribed: IsSubscribed(true), + ) + ]; + + test('Should return full mailbox with role when update role mailbox success', () async { + final mapResponseData = { + "methodResponses": [ + [ + "Mailbox/set", + { + "oldState": "105", + "newState": "107", + "created": null, + "updated": { + 'sent-id': null, + 'outbox-id': null + }, + "destroyed": null, + "notCreated": null, + "notUpdated": null, + "notDestroyed": null, + "accountId": accountId.asString, + }, + "c0" + ] + ], + "sessionState": "0" + }; + + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenAnswer((_) async => mapResponseData); + + final mailboxRecords = await mailboxAPI.setRoleDefaultMailbox( + session, + accountId, + listMailbox, + ); + + final newListMailbox = mailboxRecords.$1; + final mapErrors = mailboxRecords.$2; + + verify(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )); + expect(newListMailbox.length, listMailbox.length); + expect(mapErrors.isEmpty, isTrue); + expect( + newListMailbox.any((mailbox) => mailbox.role == PresentationMailbox.roleSent), + isTrue, + ); + expect( + newListMailbox.any((mailbox) => mailbox.role == PresentationMailbox.roleOutbox), + isTrue, + ); + }); + + test('Should return some mailbox with role when update role mailbox fail', () async { + final mapResponseData = { + "methodResponses": [ + [ + "Mailbox/set", + { + "oldState": "105", + "newState": "107", + "created": null, + "updated": { + 'sent-id': null + }, + "destroyed": null, + "notCreated": null, + "notUpdated": { + "outbox-id": { + "type": "invalidProperties", + "properties": [ + "role" + ] + } + }, + "notDestroyed": null, + "accountId": accountId.asString, + }, + "c0" + ] + ], + "sessionState": "0" + }; + + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenAnswer((_) async => mapResponseData); + + final mailboxRecords = await mailboxAPI.setRoleDefaultMailbox( + session, + accountId, + listMailbox, + ); + + final newListMailbox = mailboxRecords.$1; + final mapErrors = mailboxRecords.$2; + + verify(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )); + + expect(newListMailbox.length,listMailbox.length); + expect(mapErrors.isNotEmpty, isTrue); + expect( + newListMailbox.any((mailbox) => mailbox.role == PresentationMailbox.roleSent), + isTrue, + ); + expect( + newListMailbox.every((mailbox) => mailbox.role != PresentationMailbox.roleOutbox), + isTrue, + ); + }); + + test('Should throw exception when http client throw exception', () async { + when(httpClient.post( + '', + data: anyNamed('data'), + cancelToken: anyNamed('cancelToken'), + )).thenThrow(Exception()); + + expect( + () => mailboxAPI.setRoleDefaultMailbox(session, accountId, listMailbox), + throwsA(isA()), + ); + }); + }); + }); +}