Skip to content

Commit

Permalink
TF-942 Auto generate missing Outbox mailbox before send email
Browse files Browse the repository at this point in the history
  • Loading branch information
dab246 authored and hoangdat committed Sep 26, 2022
1 parent 1722543 commit 106a0c4
Show file tree
Hide file tree
Showing 16 changed files with 205 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

class NotFoundOutboxMailboxException implements Exception {
NotFoundOutboxMailboxException();
}
31 changes: 28 additions & 3 deletions lib/features/composer/domain/model/email_request.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@

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';

class EmailRequest with EquatableMixin {

final Email email;
final Id submissionCreateId;
final MailboxId? mailboxIdSaved;
final MailboxId? sentMailboxId;
final EmailId? emailIdDestroyed;
final Identity? identity;

EmailRequest(this.email, this.submissionCreateId, {this.mailboxIdSaved, this.emailIdDestroyed});
EmailRequest(this.email, this.submissionCreateId, {
this.sentMailboxId,
this.identity,
this.emailIdDestroyed
});

@override
List<Object?> get props => [email, submissionCreateId, mailboxIdSaved];
List<Object?> get props => [
email,
submissionCreateId,
sentMailboxId,
identity,
emailIdDestroyed
];
}

extension EmailRequestExtension on EmailRequest {

EmailRequest toEmailRequest({Email? newEmail}) {
return EmailRequest(
newEmail ?? email,
submissionCreateId,
sentMailboxId: sentMailboxId,
identity: identity,
emailIdDestroyed: emailIdDestroyed
);
}
}
13 changes: 10 additions & 3 deletions lib/features/composer/domain/usecases/send_email_interactor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';
import 'package:uuid/uuid.dart';

class SendEmailInteractor {
final EmailRepository _emailRepository;
final MailboxRepository _mailboxRepository;
final Uuid _uuid;

SendEmailInteractor(this._emailRepository, this._mailboxRepository);
SendEmailInteractor(this._emailRepository, this._mailboxRepository, this._uuid);

Stream<Either<Failure, Success>> execute(AccountId accountId, EmailRequest emailRequest) async* {
Stream<Either<Failure, Success>> execute(
AccountId accountId,
EmailRequest emailRequest,
{CreateNewMailboxRequest? mailboxRequest}
) async* {
try {
yield Right<Failure, Success>(SendingEmailState());

Expand All @@ -24,7 +31,7 @@ class SendEmailInteractor {
final currentMailboxState = listState.first;
final currentEmailState = listState.last;

final result = await _emailRepository.sendEmail(accountId, emailRequest);
final result = await _emailRepository.sendEmail(accountId, emailRequest, mailboxRequest: mailboxRequest);
if (result) {
yield Right<Failure, Success>(SendEmailSuccess(
currentEmailState: currentEmailState,
Expand Down
4 changes: 3 additions & 1 deletion lib/features/composer/presentation/composer_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import 'package:tmail_ui_user/features/upload/data/network/file_uploader.dart';
import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart';
import 'package:tmail_ui_user/features/upload/presentation/controller/upload_controller.dart';
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
import 'package:uuid/uuid.dart';
import 'package:worker_manager/worker_manager.dart';

class ComposerBindings extends BaseBindings {
Expand Down Expand Up @@ -134,7 +135,8 @@ class ComposerBindings extends BaseBindings {
Get.lazyPut(() => UploadAttachmentInteractor(Get.find<ComposerRepository>()));
Get.lazyPut(() => SendEmailInteractor(
Get.find<EmailRepository>(),
Get.find<MailboxRepository>()));
Get.find<MailboxRepository>(),
Get.find<Uuid>()));
Get.lazyPut(() => SaveEmailAsDraftsInteractor(
Get.find<EmailRepository>(),
Get.find<MailboxRepository>()));
Expand Down
94 changes: 54 additions & 40 deletions lib/features/composer/presentation/composer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import 'package:tmail_ui_user/features/composer/presentation/model/screen_displa
import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_composer_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
Expand Down Expand Up @@ -302,11 +303,7 @@ class ComposerController extends BaseController {
final userProfile = mailboxDashBoardController.userProfile.value;
_removeComposerCacheOnWebInteractor.execute();
if (userProfile != null) {
final draftEmail = await _generateEmail(
currentContext!,
mailboxDashBoardController.mapDefaultMailboxIdByRole,
userProfile,
);
final draftEmail = await _generateEmail(currentContext!, userProfile);
_saveComposerCacheOnWebInteractor.execute(draftEmail);
}
});
Expand Down Expand Up @@ -524,13 +521,13 @@ class ComposerController extends BaseController {

Future<Email> _generateEmail(
BuildContext context,
Map<Role, MailboxId> mapDefaultMailboxId,
UserProfile userProfile,
{bool asDrafts = false}
{
bool asDrafts = false,
MailboxId? draftMailboxId,
MailboxId? outboxMailboxId
}
) async {
final generateEmailId = EmailId(Id(_uuid.v1()));
final outboxMailboxId = mapDefaultMailboxId[PresentationMailbox.roleOutbox];
final draftMailboxId = mapDefaultMailboxId[PresentationMailbox.roleDrafts];
Set<EmailAddress> listFromEmailAddress = {EmailAddress(null, userProfile.email)};
if (identitySelected.value?.email?.isNotEmpty == true) {
listFromEmailAddress = {EmailAddress(
Expand All @@ -541,37 +538,48 @@ class ComposerController extends BaseController {
if (identitySelected.value?.replyTo?.isNotEmpty == true) {
listReplyToEmailAddress = identitySelected.value!.replyTo!;
}
final generatePartId = PartId(_uuid.v1());

final attachments = <EmailBodyPart>{};
attachments.addAll(uploadController.generateAttachments() ?? []);

var emailBodyText = await _getEmailBodyText(context);

if (uploadController.mapInlineAttachments.isNotEmpty) {
final mapContents = await _getMapContent(emailBodyText);
log('ComposerController::_generateEmail(): mapContents: $mapContents');
emailBodyText = mapContents.value1;
final listInlineAttachment = mapContents.value2;
final listInlineEmailBodyPart = listInlineAttachment
.map((attachment) => attachment.toEmailBodyPart(charset: 'base64'))
.toSet();
attachments.addAll(listInlineEmailBodyPart);
log('ComposerController::_generateEmail(): listInlineEmailBodyPart: $listInlineEmailBodyPart');
}

final userAgent = await userAgentPlatform;
log('ComposerController::_generateEmail(): userAgent: $userAgent');

Map<MailboxId, bool> mailboxIds = {};
if (asDrafts && draftMailboxId != null) {
mailboxIds[draftMailboxId] = true;
}
if (outboxMailboxId != null) {
mailboxIds[outboxMailboxId] = true;
}

Map<KeyWordIdentifier, bool>? mapKeywords = {};
if (asDrafts) {
mapKeywords[KeyWordIdentifier.emailDraft] = true;
}

final generateEmailId = EmailId(Id(_uuid.v1()));
final generatePartId = PartId(_uuid.v1());

return Email(
generateEmailId,
mailboxIds: asDrafts ? {draftMailboxId!: true} : {outboxMailboxId!: true},
mailboxIds: mailboxIds.isNotEmpty ? mailboxIds : null,
from: listFromEmailAddress,
to: listToEmailAddress.toSet(),
cc: listCcEmailAddress.toSet(),
bcc: listBccEmailAddress.toSet(),
replyTo: listReplyToEmailAddress,
keywords: asDrafts ? {KeyWordIdentifier.emailDraft : true} : null,
keywords: mapKeywords.isNotEmpty ? mapKeywords : null,
subject: subjectEmail.value,
htmlBody: {
EmailBodyPart(
Expand Down Expand Up @@ -687,23 +695,33 @@ class ComposerController extends BaseController {

void _handleSendMessages(BuildContext context) async {
final arguments = composerArguments.value;
final session = mailboxDashBoardController.sessionCurrent;
final mapDefaultMailboxIdByRole = mailboxDashBoardController.mapDefaultMailboxIdByRole;
final accountId = mailboxDashBoardController.accountId.value;
final sentMailboxId = mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleSent];
final outboxMailboxId = mailboxDashBoardController.outboxMailbox?.id;
log('ComposerController::_handleSendMessages(): outboxMailboxId: $outboxMailboxId');
final userProfile = mailboxDashBoardController.userProfile.value;
if (arguments != null && session != null && mapDefaultMailboxIdByRole.isNotEmpty
&& userProfile != null) {

final email = await _generateEmail(context, mapDefaultMailboxIdByRole, userProfile);
final accountId = session.accounts.keys.first;
final sentMailboxId = mapDefaultMailboxIdByRole[PresentationMailbox.roleSent];
if (arguments != null && accountId != null && userProfile != null) {
final email = await _generateEmail(context, userProfile, outboxMailboxId: outboxMailboxId);
final submissionCreateId = Id(_uuid.v1());

mailboxDashBoardController.consumeState(_sendEmailInteractor.execute(
accountId,
EmailRequest(email, submissionCreateId, mailboxIdSaved: sentMailboxId,
emailIdDestroyed: arguments.emailActionType == EmailActionType.edit
? arguments.presentationEmail?.id
: null)));
mailboxDashBoardController.consumeState(
_sendEmailInteractor.execute(
accountId,
EmailRequest(
email,
submissionCreateId,
sentMailboxId: sentMailboxId,
identity: identitySelected.value,
emailIdDestroyed: arguments.emailActionType == EmailActionType.edit
? arguments.presentationEmail?.id
: null),
mailboxRequest: outboxMailboxId == null
? CreateNewMailboxRequest(
Id(_uuid.v1()),
PresentationMailbox.outboxMailboxName)
: null
)
);

uploadController.clearInlineFileUploaded();
}
Expand Down Expand Up @@ -892,25 +910,21 @@ class ComposerController extends BaseController {
}

void saveEmailAsDrafts(BuildContext context, {bool canPop = true}) async {
log('ComposerController::saveEmailAsDrafts():');
clearFocusEditor(context);

final arguments = composerArguments.value;
final mapDefaultMailboxIdByRole = mailboxDashBoardController.mapDefaultMailboxIdByRole;
final draftMailboxId = mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleDrafts];
final userProfile = mailboxDashBoardController.userProfile.value;
final session = mailboxDashBoardController.sessionCurrent;
final accountId = mailboxDashBoardController.accountId.value;

if (arguments != null && mapDefaultMailboxIdByRole.isNotEmpty && userProfile != null && session != null) {
log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts START');
if (arguments != null && userProfile != null && accountId != null) {
final isChanged = await _isEmailChanged(context, arguments);
log('ComposerController::saveEmailAsDrafts(): saveEmailAsDrafts isChanged: $isChanged');
if (isChanged) {
final newEmail = await _generateEmail(
context,
mapDefaultMailboxIdByRole,
userProfile,
asDrafts: true);
final accountId = session.accounts.keys.first;
asDrafts: true,
draftMailboxId: draftMailboxId);
final oldEmail = arguments.presentationEmail;

if (arguments.emailActionType == EmailActionType.edit && oldEmail != null) {
Expand Down
3 changes: 2 additions & 1 deletion lib/features/email/data/datasource/email_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';

abstract class EmailDataSource {
Future<Email> getEmailContent(AccountId accountId, EmailId emailId);

Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest);
Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest, {CreateNewMailboxRequest? mailboxRequest});

Future<List<Email>> markAsRead(AccountId accountId, List<Email> emails, ReadActions readActions);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';

class EmailDataSourceImpl extends EmailDataSource {

Expand All @@ -28,9 +29,9 @@ class EmailDataSourceImpl extends EmailDataSource {
}

@override
Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest) {
Future<bool> sendEmail(AccountId accountId, EmailRequest emailRequest, {CreateNewMailboxRequest? mailboxRequest}) {
return Future.sync(() async {
return await emailAPI.sendEmail(accountId, emailRequest);
return await emailAPI.sendEmail(accountId, emailRequest, mailboxRequest: mailboxRequest);
}).catchError((error) {
throw error;
});
Expand Down
Loading

0 comments on commit 106a0c4

Please sign in to comment.