Hot fix cannot send email on cyrus server when the first open app

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-02-21 16:59:14 +07:00
committed by Dat H. Pham
parent 78dffe90b6
commit a8cc19ada2
13 changed files with 138 additions and 92 deletions
@@ -6,9 +6,7 @@ import 'package:tmail_ui_user/features/composer/presentation/composer_controller
extension GetOutboxMailboxIdForComposerExtension on ComposerController { extension GetOutboxMailboxIdForComposerExtension on ComposerController {
MailboxId? getOutboxMailboxIdForComposer() { MailboxId? getOutboxMailboxIdForComposer() {
final defaultOutboxMailbox = mailboxDashBoardController.mapDefaultMailboxIdByRole[ final defaultOutboxMailboxId = mailboxDashBoardController.outboxMailbox?.mailboxId;
PresentationMailbox.roleOutbox
];
final lowercaseOutboxRole = PresentationMailbox.roleOutbox.value.toLowerCase(); final lowercaseOutboxRole = PresentationMailbox.roleOutbox.value.toLowerCase();
return mailboxDashBoardController.mapMailboxById.entries return mailboxDashBoardController.mapMailboxById.entries
@@ -17,6 +15,6 @@ extension GetOutboxMailboxIdForComposerExtension on ComposerController {
return mailbox.emailTeamMailBoxes == identitySelected.value?.email && return mailbox.emailTeamMailBoxes == identitySelected.value?.email &&
mailbox.name?.name.toLowerCase() == lowercaseOutboxRole; mailbox.name?.name.toLowerCase() == lowercaseOutboxRole;
}) })
?.key ?? defaultOutboxMailbox; ?.key ?? defaultOutboxMailboxId;
} }
} }
@@ -174,7 +174,8 @@ class EmailAPI with HandleSetErrorMixin {
final emailSubmissionId = EmailSubmissionId(ReferenceId(ReferencePrefix.defaultPrefix, submissionCreateId)); final emailSubmissionId = EmailSubmissionId(ReferenceId(ReferencePrefix.defaultPrefix, submissionCreateId));
Map<EmailSubmissionId, PatchObject> mapEmailSubmissionUpdated = { Map<EmailSubmissionId, PatchObject> mapEmailSubmissionUpdated = {
emailSubmissionId: PatchObject({ emailSubmissionId: PatchObject({
emailRequest.sentMailboxId!.generatePath() : true, if (emailRequest.sentMailboxId != null)
emailRequest.sentMailboxId!.generatePath() : true,
outboxMailboxId!.generatePath() : null, outboxMailboxId!.generatePath() : null,
KeyWordIdentifier.emailSeen.generatePath(): true, KeyWordIdentifier.emailSeen.generatePath(): true,
KeyWordIdentifier.emailDraft.generatePath(): null KeyWordIdentifier.emailDraft.generatePath(): null
@@ -52,9 +52,9 @@ abstract class MailboxDataSource {
Future<bool> handleMailboxRightRequest(Session session, AccountId accountId, MailboxRightRequest request); Future<bool> handleMailboxRightRequest(Session session, AccountId accountId, MailboxRightRequest request);
Future<List<Mailbox>> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole); Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole);
Future<void> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox); Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox);
Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role); Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role);
@@ -141,12 +141,12 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource {
} }
@override @override
Future<List<Mailbox>> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole) { Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole) {
throw UnimplementedError(); throw UnimplementedError();
} }
@override @override
Future<List<MailboxId>> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) { Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) {
throw UnimplementedError(); throw UnimplementedError();
} }
@@ -130,14 +130,14 @@ class MailboxDataSourceImpl extends MailboxDataSource {
} }
@override @override
Future<List<Mailbox>> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole) { Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole) {
return Future.sync(() async { return Future.sync(() async {
return await mailboxAPI.createDefaultMailbox(session, accountId, listRole); return await mailboxAPI.createDefaultMailbox(session, accountId, listRole);
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
} }
@override @override
Future<void> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) { Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) {
return Future.sync(() async { return Future.sync(() async {
return await mailboxAPI.setRoleDefaultMailbox(session, accountId, listMailbox); return await mailboxAPI.setRoleDefaultMailbox(session, accountId, listMailbox);
}).catchError(_exceptionThrower.throwException); }).catchError(_exceptionThrower.throwException);
@@ -34,7 +34,6 @@ import 'package:tmail_ui_user/features/base/mixin/handle_error_mixin.dart';
import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart'; import 'package:tmail_ui_user/features/composer/domain/exceptions/set_method_exception.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/mailbox_exception.dart'; import 'package:tmail_ui_user/features/mailbox/domain/exceptions/mailbox_exception.dart';
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_method_exception.dart';
import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart'; import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_rights_exception.dart';
import 'package:tmail_ui_user/features/mailbox/domain/extensions/list_mailbox_id_extension.dart'; import 'package:tmail_ui_user/features/mailbox/domain/extensions/list_mailbox_id_extension.dart';
import 'package:tmail_ui_user/features/mailbox/domain/extensions/role_extension.dart'; import 'package:tmail_ui_user/features/mailbox/domain/extensions/role_extension.dart';
@@ -454,19 +453,19 @@ class MailboxAPI with HandleSetErrorMixin {
} }
} }
Future<List<Mailbox>> createDefaultMailbox( Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> createDefaultMailbox(
Session session, Session session,
AccountId accountId, AccountId accountId,
List<Role> listRole List<Role> listRole
) async { ) async {
final mapId = { final mapRoles = {
for (var role in listRole) for (var role in listRole)
Id(_uuid.v1()) : role Id(_uuid.v1()) : role
}; };
final mapCreate = { final mapCreate = {
for (var id in mapId.keys) for (var id in mapRoles.keys)
id : Mailbox(name: MailboxName(mapId[id]!.mailboxName), isSubscribed: IsSubscribed(true)) id : Mailbox(name: MailboxName(mapRoles[id]!.mailboxName), isSubscribed: IsSubscribed(true))
}; };
final setMailboxMethodForCreate = SetMailboxMethod(accountId) final setMailboxMethodForCreate = SetMailboxMethod(accountId)
@@ -488,53 +487,40 @@ class MailboxAPI with HandleSetErrorMixin {
); );
final mapErrors = handleSetResponse([createResponse]); final mapErrors = handleSetResponse([createResponse]);
final mapMailboxCreated = createResponse?.created ?? <Id, Mailbox>{};
if (mapErrors.isNotEmpty) { final listMailboxCreated = _convertMapToListMailbox(
throw SetMailboxMethodException(mapErrors); mapRoles: mapRoles,
} else { mapMailboxName: mapCreate,
final mapMailboxCreated = createResponse?.created ?? <Id, Mailbox>{}; mapMailboxCreated: mapMailboxCreated,
log('MailboxAPI::createDefaultMailbox:mapMailboxCreated: $mapMailboxCreated'); );
final listMailboxCreated = _convertMapToListMailbox(
mapRoles: mapId, return (listMailboxCreated, mapErrors);
mapMailboxName: mapCreate,
mapMailboxCreated: mapMailboxCreated
);
log('MailboxAPI::createDefaultMailbox:listMailboxCreated: ${listMailboxCreated.length}');
if (listMailboxCreated.isEmpty) {
throw NotFoundMailboxCreatedException();
} else {
return listMailboxCreated;
}
}
} }
List<Mailbox> _convertMapToListMailbox({ List<Mailbox> _convertMapToListMailbox({
required Map<Id, Role> mapRoles, required Map<Id, Role> mapRoles,
required Map<Id, Mailbox> mapMailboxName, required Map<Id, Mailbox> mapMailboxName,
required Map<Id, Mailbox> mapMailboxCreated required Map<Id, Mailbox> mapMailboxCreated,
}) { }) {
return mapRoles.keys return mapMailboxCreated
.where((key) => mapMailboxCreated.containsKey(key)) .entries
.map((key) { .map((mailboxEntry) {
final mailboxName = mapMailboxName[key]?.name; final id = mailboxEntry.key;
final mailboxRole = mapRoles[key]; final mailbox = mailboxEntry.value;
if (mailboxName != null && mailboxRole != null) { return mailbox.copyWith(
return mapMailboxCreated[key]?.toMailbox( name: mapMailboxName[id]?.name,
mailboxName, role: mapRoles[id],
mailboxRole: mailboxRole isSubscribed: IsSubscribed(true),
); );
} else {
return null;
}
}) })
.whereNotNull()
.toList(); .toList();
} }
Future<void> setRoleDefaultMailbox( Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> setRoleDefaultMailbox(
Session session, Session session,
AccountId accountId, AccountId accountId,
List<Mailbox> listMailbox List<Mailbox> listMailbox,
) async { ) async {
final mapUpdated = { final mapUpdated = {
for (var mailbox in listMailbox) for (var mailbox in listMailbox)
@@ -560,9 +546,27 @@ class MailboxAPI with HandleSetErrorMixin {
); );
final mapErrors = handleSetResponse([updateResponse]); final mapErrors = handleSetResponse([updateResponse]);
if (mapErrors.isNotEmpty) { final listUpdatedMailboxId = updateResponse?.updated?.keys ?? [];
throw SetMailboxMethodException(mapErrors);
if (listUpdatedMailboxId.isEmpty) {
final listMailboxWithoutRole = listMailbox
.map((mailbox) => mailbox.toMailboxWithoutRole())
.toList();
return (listMailboxWithoutRole, mapErrors);
} }
final listUpdatedMailbox = listMailbox
.map((mailbox) {
if (listUpdatedMailboxId.contains(mailbox.id!.id)) {
return mailbox;
} else {
return mailbox.toMailboxWithoutRole();
}
})
.toList();
return (listUpdatedMailbox, mapErrors);
} }
Future<GetMailboxByRoleResponse> getMailboxByRole( Future<GetMailboxByRoleResponse> getMailboxByRole(
@@ -292,12 +292,12 @@ class MailboxRepositoryImpl extends MailboxRepository {
} }
@override @override
Future<List<Mailbox>> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole) { Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole) {
return mapDataSource[DataSourceType.network]!.createDefaultMailbox(session, accountId, listRole); return mapDataSource[DataSourceType.network]!.createDefaultMailbox(session, accountId, listRole);
} }
@override @override
Future<void> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) { Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) {
return mapDataSource[DataSourceType.network]!.setRoleDefaultMailbox(session, accountId, listMailbox); return mapDataSource[DataSourceType.network]!.setRoleDefaultMailbox(session, accountId, listMailbox);
} }
@@ -1,14 +1,3 @@
import 'package:jmap_dart_client/jmap/core/error/set_error.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
class SetMailboxMethodException implements Exception {
final Map<Id, SetError> mapErrors;
SetMailboxMethodException(this.mapErrors);
}
class NotFoundMailboxCreatedException implements Exception {} class NotFoundMailboxCreatedException implements Exception {}
class NotFoundMailboxUpdatedRoleException implements Exception {} class NotFoundMailboxUpdatedRoleException implements Exception {}
@@ -49,9 +49,9 @@ abstract class MailboxRepository {
Future<bool> handleMailboxRightRequest(Session session, AccountId accountId, MailboxRightRequest request); Future<bool> handleMailboxRightRequest(Session session, AccountId accountId, MailboxRightRequest request);
Future<List<Mailbox>> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole); Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole);
Future<void> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox); Future<(List<Mailbox> mailboxes, Map<Id, SetError> mapErrors)> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox);
Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}); Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit});
} }
@@ -1,25 +1,20 @@
import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/state/success.dart';
import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
class CreateDefaultMailboxLoading extends LoadingState {} class CreateDefaultMailboxLoading extends LoadingState {}
class CreateDefaultMailboxAllSuccess extends UIActionState { class CreateDefaultMailboxAllSuccess extends UIState {
CreateDefaultMailboxAllSuccess({
jmap.State? currentEmailState, final List<Mailbox> listMailbox;
jmap.State? currentMailboxState,
}) : super(currentEmailState, currentMailboxState); CreateDefaultMailboxAllSuccess(this.listMailbox);
@override @override
List<Object?> get props => [...super.props]; List<Object?> get props => [listMailbox];
} }
class CreateDefaultMailboxFailure extends FeatureFailure { class CreateDefaultMailboxFailure extends FeatureFailure {
final jmap.State? currentMailboxState;
CreateDefaultMailboxFailure(this.currentMailboxState, dynamic exception) : super(exception: exception); CreateDefaultMailboxFailure(dynamic exception) : super(exception: exception);
@override
List<Object?> get props => [currentMailboxState, exception];
} }
@@ -4,8 +4,8 @@ import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart' as dartz; import 'package:dartz/dartz.dart' as dartz;
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/session/session.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/mail/mailbox/mailbox.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';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/create_default_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/create_default_mailbox_state.dart';
@@ -19,32 +19,48 @@ class CreateDefaultMailboxInteractor {
AccountId accountId, AccountId accountId,
List<Role> listRole List<Role> listRole
) async* { ) async* {
final currentMailboxState = await _getCurrentMailboxState(session, accountId);
try { try {
yield dartz.Right<Failure, Success>(CreateDefaultMailboxLoading()); yield dartz.Right<Failure, Success>(CreateDefaultMailboxLoading());
final listMailboxCreated = await _mailboxRepository.createDefaultMailbox( final mailboxesRecord = await _mailboxRepository.createDefaultMailbox(
session, session,
accountId, accountId,
listRole listRole
); );
await _mailboxRepository.setRoleDefaultMailbox(
final listMailboxCreated = mailboxesRecord.$1;
log('CreateDefaultMailboxInteractor::execute:listMailboxCreated = $listMailboxCreated');
if (listMailboxCreated.isEmpty) {
yield dartz.Left<Failure, Success>(CreateDefaultMailboxFailure(NotFoundMailboxCreatedException()));
return;
}
final listMailboxUpdated = await _updateRoleToListMailbox(
session, session,
accountId, accountId,
listMailboxCreated listMailboxCreated,
); );
yield dartz.Right<Failure, Success>(CreateDefaultMailboxAllSuccess(currentMailboxState: currentMailboxState));
yield dartz.Right<Failure, Success>(CreateDefaultMailboxAllSuccess(listMailboxUpdated));
} catch (e) { } catch (e) {
yield dartz.Left<Failure, Success>(CreateDefaultMailboxFailure(currentMailboxState, e)); yield dartz.Left<Failure, Success>(CreateDefaultMailboxFailure(e));
} }
} }
Future<State?> _getCurrentMailboxState(Session session, AccountId accountId) async { Future<List<Mailbox>> _updateRoleToListMailbox(
Session session,
AccountId accountId,
List<Mailbox> mailboxes,
) async {
try { try {
final currentMailboxState = await _mailboxRepository.getMailboxState(session, accountId); final mailboxUpdatedRecord = await _mailboxRepository.setRoleDefaultMailbox(
log('CreateDefaultMailboxInteractor::_getCurrentMailboxState:currentMailboxState: $currentMailboxState'); session,
return currentMailboxState; accountId,
mailboxes,
);
return mailboxUpdatedRecord.$1;
} catch (e) { } catch (e) {
return null; logError('CreateDefaultMailboxInteractor::_updateRoleToListMailbox:Exception = $e');
return mailboxes;
} }
} }
} }
@@ -45,6 +45,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_right_reques
import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_multiple_mailbox_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_multiple_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/create_default_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/create_new_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/create_new_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/delete_multiple_mailbox_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart';
@@ -203,6 +204,8 @@ class MailboxController extends BaseMailboxController
_handleUnsubscribeMultipleMailboxHasSomeSuccess(success); _handleUnsubscribeMultipleMailboxHasSomeSuccess(success);
} else if (success is SubaddressingSuccess) { } else if (success is SubaddressingSuccess) {
_handleSubaddressingSuccess(success); _handleSubaddressingSuccess(success);
} else if (success is CreateDefaultMailboxAllSuccess) {
_handleCreateDefaultFolderIfMissingSuccess(success);
} }
} }
@@ -657,6 +660,28 @@ class MailboxController extends BaseMailboxController
} }
} }
Future<void> _handleCreateDefaultFolderIfMissingSuccess(CreateDefaultMailboxAllSuccess success) async {
if (success.listMailbox.isEmpty) return;
Set<Role?> existingRoles = {};
Set<MailboxName> existingNamesWithoutParent = {};
for (var mailbox in success.listMailbox) {
if (mailbox.role != null && !existingRoles.add(mailbox.role)) continue;
if (mailbox.parentId == null && mailbox.name != null && !existingNamesWithoutParent.add(mailbox.name!)) continue;
allMailboxes.add(mailbox.toPresentationMailbox());
}
await buildTree(allMailboxes);
if (currentContext != null) {
syncAllMailboxWithDisplayName(currentContext!);
}
_setMapMailbox();
_setOutboxMailbox();
}
void _handleDataFromNavigationRouter() { void _handleDataFromNavigationRouter() {
log('MailboxController::_handleDataFromNavigationRouter():navigationRouter: $_navigationRouter'); log('MailboxController::_handleDataFromNavigationRouter():navigationRouter: $_navigationRouter');
if (!PlatformInfo.isWeb || _navigationRouter == null) { if (!PlatformInfo.isWeb || _navigationRouter == null) {
@@ -56,6 +56,24 @@ extension MailboxExtension on Mailbox {
); );
} }
Mailbox toMailboxWithoutRole() {
return Mailbox(
id: id,
name: name,
parentId: parentId,
role: null,
sortOrder: sortOrder,
totalEmails: totalEmails,
unreadEmails: unreadEmails,
totalThreads: totalThreads,
unreadThreads: unreadThreads,
myRights: myRights,
isSubscribed: isSubscribed,
namespace: namespace,
rights: rights,
);
}
Mailbox toMailbox(MailboxName mailboxName, {MailboxId? parentId, Role? mailboxRole}) { Mailbox toMailbox(MailboxName mailboxName, {MailboxId? parentId, Role? mailboxRole}) {
return Mailbox( return Mailbox(
id: id, id: id,