diff --git a/lib/features/composer/domain/model/email_request.dart b/lib/features/composer/domain/model/email_request.dart index e425d6ada..e6dd3d4ed 100644 --- a/lib/features/composer/domain/model/email_request.dart +++ b/lib/features/composer/domain/model/email_request.dart @@ -1,6 +1,5 @@ import 'package:equatable/equatable.dart'; -import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; @@ -9,30 +8,33 @@ import 'package:model/email/email_action_type.dart'; class EmailRequest with EquatableMixin { final Email email; - final Id submissionCreateId; final MailboxId? sentMailboxId; final EmailId? emailIdDestroyed; + final EmailId? emailIdAnsweredOrForwarded; final Identity? identity; final EmailActionType? emailActionType; - EmailRequest(this.email, this.submissionCreateId, { + EmailRequest( + this.email, { this.sentMailboxId, this.identity, this.emailIdDestroyed, + this.emailIdAnsweredOrForwarded, this.emailActionType }); @override List get props => [ email, - submissionCreateId, sentMailboxId, identity, emailIdDestroyed, + emailIdAnsweredOrForwarded, emailActionType ]; - bool get isEmailAnswered => emailActionType == EmailActionType.reply || emailActionType == EmailActionType.replyAll; + bool get isEmailAnswered => emailIdAnsweredOrForwarded != null && + (emailActionType == EmailActionType.reply || emailActionType == EmailActionType.replyAll); - bool get isEmailForwarded => emailActionType == EmailActionType.forward; + bool get isEmailForwarded => emailIdAnsweredOrForwarded != null && emailActionType == EmailActionType.forward; } \ No newline at end of file diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index d04396306..b31e71c89 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -807,15 +807,14 @@ class ComposerController extends BaseController { if (arguments != null && accountId != null && userProfile != null && session != null) { final email = await _generateEmail(context, userProfile, outboxMailboxId: outboxMailboxId); - final submissionCreateId = Id(_uuid.v1()); final emailRequest = EmailRequest( email, - submissionCreateId, sentMailboxId: sentMailboxId, identity: identitySelected.value, emailIdDestroyed: arguments.emailActionType == EmailActionType.edit ? arguments.presentationEmail?.id : null, + emailIdAnsweredOrForwarded: arguments.presentationEmail?.id, emailActionType: arguments.emailActionType ); final mailboxRequest = outboxMailboxId == null diff --git a/lib/features/email/data/network/email_api.dart b/lib/features/email/data/network/email_api.dart index d0d7e4684..d1b727533 100644 --- a/lib/features/email/data/network/email_api.dart +++ b/lib/features/email/data/network/email_api.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; +import 'package:collection/collection.dart'; import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; @@ -13,10 +14,12 @@ import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart import 'package:jmap_dart_client/jmap/core/capability/core_capability.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/core/method/response/set_response.dart'; import 'package:jmap_dart_client/jmap/core/patch_object.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/reference_id.dart'; import 'package:jmap_dart_client/jmap/core/reference_prefix.dart'; +import 'package:jmap_dart_client/jmap/core/request/request_invocation.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; @@ -141,32 +144,48 @@ class EmailAPI with HandleSetErrorMixin { final setEmailMethod = SetEmailMethod(accountId) ..addCreate(idCreateMethod, emailNeedsToBeCreated); - final setEmailInvocation = requestBuilder.invocation(setEmailMethod); + final submissionCreateId = Id(_uuid.v1()); + final mailFrom = Address(emailNeedsToBeCreated.from?.first.email ?? ''); + final recipientsList = emailNeedsToBeCreated.getRecipientEmailAddressList() + .map((emailAddress) => Address(emailAddress)) + .toSet(); + final emailSubmissionId = EmailSubmissionId(ReferenceId(ReferencePrefix.defaultPrefix, submissionCreateId)); + Map mapEmailSubmissionUpdated = { + emailSubmissionId: PatchObject({ + emailRequest.sentMailboxId!.generatePath() : true, + outboxMailboxId!.generatePath() : null, + KeyWordIdentifier.emailSeen.generatePath(): true, + KeyWordIdentifier.emailDraft.generatePath(): null + }) + }; + final emailSubmission = EmailSubmission( + identityId: emailRequest.identity?.id?.id, + emailId: EmailId(ReferenceId(ReferencePrefix.defaultPrefix, idCreateMethod)), + envelope: Envelope(mailFrom, recipientsList)); final setEmailSubmissionMethod = SetEmailSubmissionMethod(accountId) - ..addCreate( - emailRequest.submissionCreateId, - EmailSubmission( - identityId: emailRequest.identity?.id?.id, - emailId: EmailId(ReferenceId(ReferencePrefix.defaultPrefix, idCreateMethod)), - envelope: Envelope( - Address(emailNeedsToBeCreated.from?.first.email ?? ''), - emailNeedsToBeCreated.getRecipientEmailAddressList().map((emailAddress) => Address(emailAddress)).toSet() - ) - )) - ..addOnSuccessUpdateEmail({ - EmailSubmissionId(ReferenceId(ReferencePrefix.defaultPrefix, emailRequest.submissionCreateId)): PatchObject({ - emailRequest.sentMailboxId!.generatePath() : true, - outboxMailboxId!.generatePath() : null, - KeyWordIdentifier.emailSeen.generatePath(): true, - KeyWordIdentifier.emailDraft.generatePath(): null, - KeyWordIdentifier.emailAnswered.generatePath(): emailRequest.isEmailAnswered ? true : null, - KeyWordIdentifier.emailForwarded.generatePath(): emailRequest.isEmailForwarded ? true : null - }) - }); + ..addCreate(submissionCreateId, emailSubmission) + ..addOnSuccessUpdateEmail(mapEmailSubmissionUpdated); + final setEmailInvocation = requestBuilder.invocation(setEmailMethod); final setEmailSubmissionInvocation = requestBuilder.invocation(setEmailSubmissionMethod); + SetEmailMethod? markAsAnsweredOrForwardedSetMethod; + RequestInvocation? markAsAnsweredOrForwardedInvocation; + SetEmailResponse? markAsAnsweredOrForwardedSetResponse; + + if (emailRequest.isEmailAnswered) { + markAsAnsweredOrForwardedSetMethod = SetEmailMethod(accountId) + ..addUpdates([emailRequest.emailIdAnsweredOrForwarded!].generateMapUpdateObjectMarkAsAnswered()); + + markAsAnsweredOrForwardedInvocation = requestBuilder.invocation(markAsAnsweredOrForwardedSetMethod); + } else if (emailRequest.isEmailForwarded) { + markAsAnsweredOrForwardedSetMethod = SetEmailMethod(accountId) + ..addUpdates([emailRequest.emailIdAnsweredOrForwarded!].generateMapUpdateObjectMarkAsForwarded()); + + markAsAnsweredOrForwardedInvocation = requestBuilder.invocation(markAsAnsweredOrForwardedSetMethod); + } + final capabilities = setEmailSubmissionMethod.requiredCapabilities .toCapabilitiesSupportTeamMailboxes(session, accountId); @@ -184,11 +203,18 @@ class EmailAPI with HandleSetErrorMixin { SetEmailSubmissionResponse.deserialize, methodName: setEmailInvocation.methodName); + if (markAsAnsweredOrForwardedInvocation != null) { + markAsAnsweredOrForwardedSetResponse = response.parse( + markAsAnsweredOrForwardedInvocation.methodCallId, + SetEmailResponse.deserialize); + } + final emailCreated = setEmailResponse?.created?[idCreateMethod]; - final listEntriesErrors = _handleSetEmailResponse( - response: setEmailResponse, - submissionResponse: setEmailSubmissionResponse - ); + final listEntriesErrors = _handleSetEmailResponse([ + setEmailResponse, + setEmailSubmissionResponse, + markAsAnsweredOrForwardedSetResponse + ]); final mapErrors = Map.fromEntries(listEntriesErrors); if (emailCreated != null && mapErrors.isEmpty) { @@ -198,12 +224,14 @@ class EmailAPI with HandleSetErrorMixin { } } - List> _handleSetEmailResponse({ - SetEmailResponse? response, - SetEmailSubmissionResponse? submissionResponse - }) { + List> _handleSetEmailResponse(List listSetResponse) { + final listSetResponseNotNull = listSetResponse.whereNotNull().toList(); + if (listSetResponseNotNull.isEmpty) { + return []; + } + final List> remainedErrors = []; - if (response != null) { + for (var response in listSetResponseNotNull) { handleSetErrors( notDestroyedError: response.notDestroyed, notUpdatedError: response.notUpdated, @@ -214,17 +242,6 @@ class EmailAPI with HandleSetErrorMixin { } ); } - if (submissionResponse != null) { - handleSetErrors( - notDestroyedError: submissionResponse.notDestroyed, - notUpdatedError: submissionResponse.notUpdated, - notCreatedError: submissionResponse.notCreated, - unCatchErrorHandler: (setErrorEntry) { - remainedErrors.add(setErrorEntry); - return false; - } - ); - } return remainedErrors; } @@ -428,7 +445,6 @@ class EmailAPI with HandleSetErrorMixin { return listEmailIdRequest.where((emailId) => listUpdated.expand((e) => e).toList().contains(emailId.id)).toList(); } - Future> markAsStar( Session session, AccountId accountId, @@ -490,7 +506,7 @@ class EmailAPI with HandleSetErrorMixin { ); final emailCreated = setEmailResponse?.created?[idCreateMethod]; - final listEntriesErrors = _handleSetEmailResponse(response: setEmailResponse); + final listEntriesErrors = _handleSetEmailResponse([setEmailResponse]); final mapErrors = Map.fromEntries(listEntriesErrors); if (emailCreated != null && mapErrors.isEmpty) { @@ -554,7 +570,7 @@ class EmailAPI with HandleSetErrorMixin { ); final emailUpdated = setEmailResponse?.created?[idCreateMethod]; - final listEntriesErrors = _handleSetEmailResponse(response: setEmailResponse); + final listEntriesErrors = _handleSetEmailResponse([setEmailResponse]); final mapErrors = Map.fromEntries(listEntriesErrors); if (emailUpdated != null && mapErrors.isEmpty) { diff --git a/model/lib/extensions/keyword_identifier_extension.dart b/model/lib/extensions/keyword_identifier_extension.dart index 909b12640..84fb93e94 100644 --- a/model/lib/extensions/keyword_identifier_extension.dart +++ b/model/lib/extensions/keyword_identifier_extension.dart @@ -19,4 +19,16 @@ extension KeyWordIdentifierExtension on KeyWordIdentifier { generatePath(): markStarAction == MarkStarAction.markStar ? true : null }); } + + PatchObject generateAnsweredActionPath() { + return PatchObject({ + generatePath(): true + }); + } + + PatchObject generateForwardedActionPath() { + return PatchObject({ + generatePath(): true + }); + } } \ No newline at end of file diff --git a/model/lib/extensions/list_email_id_extension.dart b/model/lib/extensions/list_email_id_extension.dart index e5f344a17..82fbebdcd 100644 --- a/model/lib/extensions/list_email_id_extension.dart +++ b/model/lib/extensions/list_email_id_extension.dart @@ -10,34 +10,44 @@ extension ListEmailIdExtension on List { List toIds() => map((emailId) => emailId.id).toList(); Map generateMapUpdateObjectMarkAsRead(ReadActions readActions) { - final Map maps = {}; - forEach((emailId) { - maps[emailId.id] = KeyWordIdentifier.emailSeen.generateReadActionPath(readActions); - }); - return maps; + return { + for (var emailId in this) + emailId.id: KeyWordIdentifier.emailSeen.generateReadActionPath(readActions) + }; } Map generateMapUpdateObjectMoveToMailbox(MailboxId currentMailboxId, MailboxId destinationMailboxId) { - final Map maps = {}; - forEach((emailId) { - maps[emailId.id] = currentMailboxId.generateMoveToMailboxActionPath(destinationMailboxId); - }); - return maps; + return { + for (var emailId in this) + emailId.id: currentMailboxId.generateMoveToMailboxActionPath(destinationMailboxId) + }; } Map generateMapUpdateObjectMarkAsStar(MarkStarAction markStarAction) { - final Map maps = {}; - forEach((emailId) { - maps[emailId.id] = KeyWordIdentifier.emailFlagged.generateMarkStarActionPath(markStarAction); - }); - return maps; + return { + for (var emailId in this) + emailId.id: KeyWordIdentifier.emailFlagged.generateMarkStarActionPath(markStarAction) + }; } Map generateMapUpdateObjectMarkAsSpam(MailboxId spamMailboxId) { - final Map maps = {}; - forEach((emailId) { - maps[emailId.id] = spamMailboxId.generateActionPath(); - }); - return maps; + return { + for (var emailId in this) + emailId.id: spamMailboxId.generateActionPath() + }; + } + + Map generateMapUpdateObjectMarkAsAnswered() { + return { + for (var emailId in this) + emailId.id: KeyWordIdentifier.emailAnswered.generateAnsweredActionPath() + }; + } + + Map generateMapUpdateObjectMarkAsForwarded() { + return { + for (var emailId in this) + emailId.id: KeyWordIdentifier.emailForwarded.generateForwardedActionPath() + }; } } \ No newline at end of file