Skip to content

Commit

Permalink
TF-2101 Handle restore deleted messages
Browse files Browse the repository at this point in the history
(cherry picked from commit e675f98)
  • Loading branch information
hieutbui authored and hoangdat committed Jan 8, 2024
1 parent 4f6b500 commit 71dc206
Show file tree
Hide file tree
Showing 30 changed files with 456 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,55 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:email_recovery/email_recovery/email_recovery_action.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:tmail_ui_user/features/base/state/ui_action_state.dart';

class GetRestoredDeletedMessageLoading extends LoadingState {}

class GetRestoredDeletedMessageSuccess extends UIState {
class GetRestoredDeletedMessageSuccess extends UIActionState {
final EmailRecoveryAction emailRecoveryAction;


GetRestoredDeletedMessageSuccess(
this.emailRecoveryAction,
{
jmap.State? currentMailboxState,
}
) : super(null, currentMailboxState);

GetRestoredDeletedMessageSuccess(this.emailRecoveryAction);
@override
List<Object?> get props => [emailRecoveryAction, ...super.props];
}

class GetRestoredDeletedMessageCompleted extends GetRestoredDeletedMessageSuccess {
final Mailbox? recoveredMailbox;

GetRestoredDeletedMessageCompleted(
EmailRecoveryAction emailRecoveryAction,
{this.recoveredMailbox}
) : super(emailRecoveryAction);

@override
List<Object> get props => [emailRecoveryAction];
List<Object?> get props => [emailRecoveryAction, recoveredMailbox];
}

class GetRestoredDeletedMessageWaiting extends GetRestoredDeletedMessageSuccess {
GetRestoredDeletedMessageWaiting(
EmailRecoveryAction emailRecoveryAction,
) : super(emailRecoveryAction);
}

class GetRestoredDeletedMessageInProgress extends GetRestoredDeletedMessageSuccess {
GetRestoredDeletedMessageInProgress(
EmailRecoveryAction emailRecoveryAction,
) : super(emailRecoveryAction);
}

class GetRestoredDeletedMessageCanceled extends GetRestoredDeletedMessageSuccess {
GetRestoredDeletedMessageCanceled(
EmailRecoveryAction emailRecoveryAction,
) : super(emailRecoveryAction);
}

class GetRestoredDeletedMessageFailure extends FeatureFailure {
Expand Down
15 changes: 11 additions & 4 deletions lib/features/email/domain/state/restore_deleted_message_state.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:email_recovery/email_recovery/email_recovery_action.dart';
import 'package:tmail_ui_user/features/base/state/ui_action_state.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;

class RestoreDeletedMessageLoading extends LoadingState {}

class RestoreDeletedMessageSuccess extends UIState {
class RestoreDeletedMessageSuccess extends UIActionState {
final EmailRecoveryAction emailRecoveryAction;

RestoreDeletedMessageSuccess(this.emailRecoveryAction);

RestoreDeletedMessageSuccess(
this.emailRecoveryAction,
{
jmap.State? currentMailboxState,
}
) : super(null, currentMailboxState);

@override
List<Object> get props => [emailRecoveryAction];
List<Object?> get props => [emailRecoveryAction, ...super.props];
}

class RestoreDeletedMessageFailure extends FeatureFailure {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,56 @@ import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:email_recovery/email_recovery/email_recovery_action_id.dart';
import 'package:email_recovery/email_recovery/email_recovery_status.dart.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/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_restored_deleted_message_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';

class GetRestoredDeletedMessageInterator {
final EmailRepository _emailRepository;
final MailboxRepository _mailboxRepository;

GetRestoredDeletedMessageInterator(this._emailRepository);
GetRestoredDeletedMessageInterator(this._emailRepository, this._mailboxRepository);

Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId,
EmailRecoveryActionId emailRecoveryActionId,
) async* {
try {
yield Right<Failure, Success>(GetRestoredDeletedMessageLoading());

final emailRecovery = await _emailRepository.getRestoredDeletedMessage(emailRecoveryActionId);
yield Right<Failure, Success>(GetRestoredDeletedMessageSuccess(emailRecovery));

switch (emailRecovery.status) {
case EmailRecoveryStatus.completed:
final getMailboxByRoleResponse = await _mailboxRepository.getMailboxByRole(
session,
accountId,
Role('Restored-Messages')
);
final recoveredMailbox = getMailboxByRoleResponse.mailbox;

yield Right<Failure, Success>(GetRestoredDeletedMessageCompleted(emailRecovery, recoveredMailbox: recoveredMailbox));
break;
case EmailRecoveryStatus.failed:
yield Left<Failure, Success>(GetRestoredDeletedMessageFailure(null));
break;
case EmailRecoveryStatus.inProgress:
yield Right<Failure, Success>(GetRestoredDeletedMessageInProgress(emailRecovery));
break;
case EmailRecoveryStatus.waiting:
yield Right<Failure, Success>(GetRestoredDeletedMessageWaiting(emailRecovery));
break;
case EmailRecoveryStatus.canceled:
yield Right<Failure, Success>(GetRestoredDeletedMessageCanceled(emailRecovery));
break;
default:
yield Left<Failure, Success>(GetRestoredDeletedMessageFailure(null));
}
} catch (e) {
yield Left<Failure, Success>(GetRestoredDeletedMessageFailure(e));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@ import 'dart:async';
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/session/session.dart';
import 'package:tmail_ui_user/features/email/domain/model/restore_deleted_message_request.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/restore_deleted_message_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart';

class RestoredDeletedMessageInteractor {
final EmailRepository _emailRepository;
final MailboxRepository _mailboxRepository;

RestoredDeletedMessageInteractor(this._emailRepository);
RestoredDeletedMessageInteractor(this._emailRepository, this._mailboxRepository);

Stream<Either<Failure, Success>> execute(
Session session,
AccountId accountId,
RestoredDeletedMessageRequest newRecoveryRequest,
) async* {
try {
yield Right<Failure, Success>(RestoreDeletedMessageLoading());
final currentMailboxState = await _mailboxRepository.getMailboxState(session, accountId);
final emailRecovery = await _emailRepository.restoreDeletedMessage(newRecoveryRequest);
yield Right<Failure, Success>(RestoreDeletedMessageSuccess(emailRecovery));
yield Right<Failure, Success>(RestoreDeletedMessageSuccess(emailRecovery, currentMailboxState: currentMailboxState));
} catch (e) {
yield Left<Failure, Success>(RestoreDeletedMessageFailure(e));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,10 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin {
void onRestore(BuildContext context) {
KeyboardUtils.hideKeyboard(context);

final UTCDate? deletedBefore;
final UTCDate? deletedAfter;
final UTCDate? receivedBefore;
final UTCDate? receivedAfter;
UTCDate? deletedBefore;
UTCDate? deletedAfter;
UTCDate? receivedBefore;
UTCDate? receivedAfter;
if (deletionDateFieldSelected.value == EmailRecoveryTimeType.customRange) {
deletedBefore = endDeletionDate.value?.toUTCDate();
deletedAfter = startDeletionDate.value?.toUTCDate();
Expand Down Expand Up @@ -343,6 +343,9 @@ class EmailRecoveryController extends BaseController with DateRangePickerMixin {
focusManager.subjectFieldFocusNode.removeListener(_onSubjectFieldFocusChanged);
focusManager.recipientsFieldFocusNode.removeListener(_onRecipientsFieldFocusChanged);
focusManager.senderFieldFocusNode.removeListener(_onSenderFieldFocusChanged);
subjectFieldInputController.dispose();
recipientsFieldInputController.dispose();
senderFieldInputController.dispose();
focusManager.dispose();
super.dispose();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ class EmailRecoveryFormDesktopBuilder extends GetWidget<EmailRecoveryController>
Obx(() => CheckBoxHasAttachmentWidget(
hasAttachmentValue: controller.hasAttachment.value,
currentFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
nextFocusNode: controller.focusManager.createButtonFocusNode,
onChanged: (value) => controller.onChangeHasAttachment(value),
)),
SizedBox(width: controller.responsiveUtils.getDeviceWidth(context) * 0.04),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ class EmailRecoveryFormMobileBuilder extends GetWidget<EmailRecoveryController>
Obx(() => CheckBoxHasAttachmentWidget(
hasAttachmentValue: controller.hasAttachment.value,
currentFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
nextFocusNode: controller.focusManager.deletionDateFieldFocusNode,
onChanged: (value) => controller.onChangeHasAttachment(value),
))
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ class EmailRecoveryFormTabletBuilder extends GetWidget<EmailRecoveryController>
Obx(() => CheckBoxHasAttachmentWidget(
hasAttachmentValue: controller.hasAttachment.value,
currentFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
nextFocusNode: controller.focusManager.deletionDateFieldFocusNode,
onChanged: (value) => controller.onChangeHasAttachment(value),
)),
SizedBox(width: controller.responsiveUtils.getDeviceWidth(context) * 0.04),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/extensions/string_extension.dart';
import 'package:flutter/material.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/model.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import 'package:tmail_ui_user/features/email_recovery/presentation/styles/text_i
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/suggestion_item_widget.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/widgets/text_input_field/suggestion_tag_item_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/suggesstion_email_address.dart';
import 'package:tmail_ui_user/main/utils/app_constants.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';

typedef OnSuggestionEmailAddress = Future<List<EmailAddress>> Function(String word);
typedef OnUpdateListEmailAddressAction = void Function(EmailRecoveryField field, List<EmailAddress> newDate);
Expand Down Expand Up @@ -325,7 +325,7 @@ class _TextInputFieldSuggestionWidgetState extends State<TextInputFieldSuggestio

final tmailSuggestion = List<SuggestionEmailAddress>.empty(growable: true);
if (
processedQuery.length >= AppConstants.limitCharToStartSearch
processedQuery.length >= AppConfig.limitCharToStartSearch
&& widget.onSuggestionEmailAddress != null
) {
final listEmailAddress = await widget.onSuggestionEmailAddress!(processedQuery);
Expand Down
3 changes: 3 additions & 0 deletions lib/features/mailbox/data/datasource/mailbox_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart';
Expand Down Expand Up @@ -51,4 +52,6 @@ abstract class MailboxDataSource {
Future<List<Mailbox>> createDefaultMailbox(Session session, AccountId accountId, List<Role> listRole);

Future<void> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox);

Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.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/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/data/datasource/mailbox_datasource.dart';
import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart';
import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart';
Expand Down Expand Up @@ -104,4 +106,9 @@ class MailboxCacheDataSourceImpl extends MailboxDataSource {
Future<List<MailboxId>> setRoleDefaultMailbox(Session session, AccountId accountId, List<Mailbox> listMailbox) {
throw UnimplementedError();
}

@override
Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}) {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.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/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
Expand All @@ -17,6 +18,7 @@ import 'package:tmail_ui_user/features/mailbox/data/model/mailbox_change_respons
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart';
import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_isolate_worker.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/rename_mailbox_request.dart';
Expand Down Expand Up @@ -132,4 +134,11 @@ class MailboxDataSourceImpl extends MailboxDataSource {
return await mailboxAPI.setRoleDefaultMailbox(session, accountId, listMailbox);
}).catchError(_exceptionThrower.throwException);
}

@override
Future<GetMailboxByRoleResponse> getMailboxByRole(Session session, AccountId accountId, Role role, {UnsignedInt? limit}) {
return Future.sync(() async {
return await mailboxAPI.getMailboxByRole(session, accountId, role);
}).catchError(_exceptionThrower.throwException);
}
}
47 changes: 47 additions & 0 deletions lib/features/mailbox/data/network/mailbox_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import 'package:jmap_dart_client/jmap/mail/mailbox/changes/changes_mailbox_respo
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_method.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_filter_condition.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/query/query_mailbox_method.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/set/set_mailbox_method.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/set/set_mailbox_response.dart';
import 'package:model/error_type_handler/set_method_error_handler_mixin.dart';
Expand All @@ -32,6 +34,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/exceptions/set_mailbox_met
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/model/create_new_mailbox_request.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/get_mailbox_by_role_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_response.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/mailbox_subscribe_state.dart';
import 'package:tmail_ui_user/features/mailbox/domain/model/move_mailbox_request.dart';
Expand Down Expand Up @@ -499,4 +502,48 @@ class MailboxAPI with HandleSetErrorMixin {
throw SetMailboxMethodException(mapErrors);
}
}

Future<GetMailboxByRoleResponse> getMailboxByRole(
Session session,
AccountId accountId,
Role role,
{
UnsignedInt? limit
}
) async {
const int defaultLimit = 1;
final processingInvocation = ProcessingInvocation();
final requestBuilder = JmapRequestBuilder(httpClient, processingInvocation);
final mailboxQueryMethod = QueryMailboxMethod(accountId)..addLimit(limit ?? UnsignedInt(defaultLimit));

final mailboxFilterCondition = MailboxFilterCondition(role: role);
mailboxQueryMethod.addFilters(mailboxFilterCondition);

final mailboxQueryMethodInvocation = requestBuilder.invocation(mailboxQueryMethod);
final getMailBoxMethod = GetMailboxMethod(accountId)
..addReferenceIds(processingInvocation.createResultReference(
mailboxQueryMethodInvocation.methodCallId,
ReferencePath.idsPath,
));
final getMailboxInvocation = requestBuilder.invocation(getMailBoxMethod);

final capabilities = getMailBoxMethod.requiredCapabilities
.toCapabilitiesSupportTeamMailboxes(session, accountId);

final result = await (requestBuilder
..usings(capabilities))
.build()
.execute();

final mailboxResponse = result.parse<GetMailboxResponse>(
getMailboxInvocation.methodCallId,
GetMailboxResponse.deserialize
);

if (mailboxResponse?.list.isNotEmpty == true) {
return GetMailboxByRoleResponse(mailbox: mailboxResponse!.list.first);
} else {
throw NotFoundMailboxException();
}
}
}
Loading

0 comments on commit 71dc206

Please sign in to comment.