TF-3082 Restore identity from cache

This commit is contained in:
DatDang
2024-08-22 09:13:04 +07:00
committed by Dat H. Pham
parent fdbbf855b6
commit 5a1fdbb123
20 changed files with 456 additions and 45 deletions
@@ -7,4 +7,10 @@ abstract class IdentityCreatorDataSource {
AccountId accountId,
UserName userName,
{required IdentityCache identityCache});
Future<IdentityCache> getIdentityCacheOnWeb(
AccountId accountId,
UserName userName);
Future<void> removeIdentityCacheOnWeb();
}
@@ -1,5 +1,7 @@
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:core/domain/exceptions/web_session_exception.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:model/extensions/account_id_extensions.dart';
@@ -31,6 +33,31 @@ class LocalIdentityCreatorDataSourceImpl implements IdentityCreatorDataSource {
window.sessionStorage.addAll(entries);
}).catchError(_exceptionThrower.throwException);
}
@override
Future<IdentityCache> getIdentityCacheOnWeb(
AccountId accountId,
UserName userName
) async {
return Future.sync(() {
final cacheKey = _generateTupleKey(accountId, userName);
final result = window.sessionStorage.entries.firstWhereOrNull(
(entry) => entry.key == cacheKey);
if (result != null) {
return IdentityCacheModel.fromJson(jsonDecode(result.value));
} else {
throw NotFoundInWebSessionException();
}
}).catchError(_exceptionThrower.throwException);
}
@override
Future<void> removeIdentityCacheOnWeb() async {
return Future.sync(() {
window.sessionStorage.removeWhere(
(key, value) => key.startsWith(LocalIdentityCreatorDataSourceImpl.sessionStorageKeyword));
}).catchError(_exceptionThrower.throwException);
}
String _generateTupleKey(AccountId accountId, UserName userName) {
return TupleKey(
@@ -18,4 +18,16 @@ class IdentityCreatorRepositoryImpl implements IdentityCreatorRepository {
accountId,
userName,
identityCache: identityCache);
@override
Future<IdentityCache> getIdentityCacheOnWeb(
AccountId accountId,
UserName userName
) => _identityCreatorDataSource.getIdentityCacheOnWeb(
accountId,
userName);
@override
Future<void> removeIdentityCacheOnWeb()
=> _identityCreatorDataSource.removeIdentityCacheOnWeb();
}
@@ -7,4 +7,10 @@ abstract class IdentityCreatorRepository {
AccountId accountId,
UserName userName,
{required IdentityCache identityCache});
Future<IdentityCache> getIdentityCacheOnWeb(
AccountId accountId,
UserName userName);
Future<void> removeIdentityCacheOnWeb();
}
@@ -0,0 +1,18 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/model/identity_cache.dart';
class GettingIdentityCacheOnWeb extends LoadingState {}
class GetIdentityCacheOnWebSuccess extends UIState {
GetIdentityCacheOnWebSuccess(this.identityCache);
final IdentityCache? identityCache;
@override
List<Object?> get props => [identityCache];
}
class GetIdentityCacheOnWebFailure extends FeatureFailure {
GetIdentityCacheOnWebFailure({super.exception});
}
@@ -0,0 +1,10 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class RemovingIdentityCacheOnWeb extends LoadingState {}
class RemoveIdentityCacheOnWebSuccess extends UIState {}
class RemoveIdentityCacheOnWebFailure extends FeatureFailure {
RemoveIdentityCacheOnWebFailure({super.exception});
}
@@ -0,0 +1,31 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/repository/identity_creator_repository.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/state/get_identity_cache_on_web_state.dart';
class GetIdentityCacheOnWebInteractor {
GetIdentityCacheOnWebInteractor(this._identityCreatorRepository);
final IdentityCreatorRepository _identityCreatorRepository;
Stream<Either<Failure, Success>> execute(
AccountId accountId,
UserName userName
) async* {
try {
yield Right(GettingIdentityCacheOnWeb());
final result = await _identityCreatorRepository.getIdentityCacheOnWeb(
accountId,
userName);
yield Right(GetIdentityCacheOnWebSuccess(result));
} catch (exception) {
logError("$runtimeType::execute: $exception");
yield Left(GetIdentityCacheOnWebFailure(exception: exception));
}
}
}
@@ -0,0 +1,24 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/repository/identity_creator_repository.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/state/remove_identity_cache_on_web_state.dart';
class RemoveIdentityCacheOnWebInteractor {
RemoveIdentityCacheOnWebInteractor(this._identityCreatorRepository);
final IdentityCreatorRepository _identityCreatorRepository;
Stream<Either<Failure, Success>> execute() async* {
try {
yield Right(RemovingIdentityCacheOnWeb());
await _identityCreatorRepository.removeIdentityCacheOnWeb();
yield Right(RemoveIdentityCacheOnWebSuccess());
} catch (exception) {
logError("$runtimeType::execute: $exception");
yield Left(RemoveIdentityCacheOnWebFailure(exception: exception));
}
}
}
@@ -352,43 +352,31 @@ class IdentityCreatorController extends BaseController with DragDropFileMixin im
listEmailAddressOfReplyTo.value = listEmailAddressOfReplyTo.toSet().toList();
listEmailAddressDefault.value = listEmailAddressDefault.toSet().toList();
if (actionType.value == IdentityActionType.edit && identity != null) {
if (identity?.replyTo?.isNotEmpty == true) {
try {
replyToOfIdentity.value = listEmailAddressOfReplyTo
.firstWhere((emailAddress) => emailAddress == identity?.replyTo!.first);
} catch(e) {
replyToOfIdentity.value = noneEmailAddress;
}
} else {
if (identity?.replyTo?.isNotEmpty == true) {
replyToOfIdentity.value = listEmailAddressOfReplyTo
.firstWhereOrNull((emailAddress) => emailAddress == identity!.replyTo!.first);
if (replyToOfIdentity.value == null && identity!.replyTo!.first == noneEmailAddress) {
replyToOfIdentity.value = noneEmailAddress;
}
if (identity?.bcc?.isNotEmpty == true) {
bccOfIdentity.value = identity?.bcc!.first;
inputBccIdentityController.text = identity?.bcc!.first.emailAddress ?? '';
} else {
bccOfIdentity.value = null;
}
if (identity?.email?.isNotEmpty == true) {
try {
emailOfIdentity.value = listEmailAddressDefault
.firstWhere((emailAddress) => emailAddress.email == identity?.email);
} catch(e) {
emailOfIdentity.value = null;
}
} else {
emailOfIdentity.value = listEmailAddressDefault.isNotEmpty
? listEmailAddressDefault.first
: null;
}
} else if (actionType.value == IdentityActionType.edit) {
replyToOfIdentity.value = noneEmailAddress;
} else {
replyToOfIdentity.value = null;
}
if (identity?.bcc?.isNotEmpty == true) {
bccOfIdentity.value = identity!.bcc!.first;
inputBccIdentityController.text = identity!.bcc!.first.emailAddress;
} else {
bccOfIdentity.value = null;
emailOfIdentity.value = listEmailAddressDefault.isNotEmpty
? listEmailAddressDefault.first
: null;
}
if (identity?.email?.isNotEmpty == true) {
emailOfIdentity.value = listEmailAddressDefault
.firstWhereOrNull((emailAddress) => emailAddress.email == identity!.email);
} else {
emailOfIdentity.value = listEmailAddressDefault.firstOrNull;
}
}
@@ -486,16 +474,19 @@ class IdentityCreatorController extends BaseController with DragDropFileMixin im
Future<({
Identity identity,
PublicAssetsInIdentityArguments publicAssetsInIdentityArguments
})> _generateIdentityAndPublicAssetArguments() async {
})> _generateIdentityAndPublicAssetArguments({bool forCache = false}) async {
final signatureHtmlText = PlatformInfo.isWeb
? contentHtmlEditor
: await _getSignatureHtmlText();
final bccAddress = bccOfIdentity.value != null && bccOfIdentity.value != noneEmailAddress
? {bccOfIdentity.value!}
: <EmailAddress>{};
final replyToAddress = replyToOfIdentity.value != null && replyToOfIdentity.value != noneEmailAddress
? {replyToOfIdentity.value!}
: <EmailAddress>{};
Set<EmailAddress> replyToAddress;
if (replyToOfIdentity.value != null && (replyToOfIdentity.value != noneEmailAddress || forCache)) {
replyToAddress = {replyToOfIdentity.value!};
} else {
replyToAddress = {};
}
final sortOrder = isDefaultIdentitySupported.isTrue
? UnsignedInt(isDefaultIdentity.value ? 0 : 100)
@@ -924,7 +915,8 @@ class IdentityCreatorController extends BaseController with DragDropFileMixin im
Future<void> _saveIdentityCacheOnWebAction() async {
if (accountId != null && session?.username != null) {
final cacheArguments = await _generateIdentityAndPublicAssetArguments();
final cacheArguments = await _generateIdentityAndPublicAssetArguments(
forCache: true);
final identityCache = IdentityCache(
identity: cacheArguments.identity,
identityActionType: actionType.value,
@@ -0,0 +1,61 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
import 'package:tmail_ui_user/features/identity_creator/data/datasource/identity_creator_data_source.dart';
import 'package:tmail_ui_user/features/identity_creator/data/datasource_impl/local_identity_creator_data_source_impl.dart';
import 'package:tmail_ui_user/features/identity_creator/data/repository/identity_creator_repository_impl.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/repository/identity_creator_repository.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/usecase/get_identity_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/features/identity_creator/domain/usecase/remove_identity_cache_on_web_interactor.dart';
import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
class RestoreIdentityCacheInteractorBindings extends InteractorsBindings {
static const _tag = BindingTag.restoreIdentityCacheInteractorBindingsTag;
@override
void bindingsDataSource() {
Get.lazyPut<IdentityCreatorDataSource>(
() => Get.find<LocalIdentityCreatorDataSourceImpl>(tag: _tag),
tag: _tag);
}
@override
void bindingsDataSourceImpl() {
Get.lazyPut(
() => LocalIdentityCreatorDataSourceImpl(
Get.find<CacheExceptionThrower>()),
tag: _tag);
}
@override
void bindingsInteractor() {
Get.lazyPut(
() => GetIdentityCacheOnWebInteractor(
Get.find<IdentityCreatorRepository>(tag: _tag)),
tag: _tag);
Get.lazyPut(
() => RemoveIdentityCacheOnWebInteractor(
Get.find<IdentityCreatorRepository>(tag: _tag)),
tag: _tag);
}
@override
void bindingsRepository() {
Get.lazyPut<IdentityCreatorRepository>(
() => Get.find<IdentityCreatorRepositoryImpl>(tag: _tag),
tag: _tag);
}
@override
void bindingsRepositoryImpl() {
Get.lazyPut(
() => IdentityCreatorRepositoryImpl(
Get.find<IdentityCreatorDataSource>(tag: _tag)),
tag: _tag);
}
void close() {
Get.delete<GetIdentityCacheOnWebInteractor>(tag: _tag);
Get.delete<RemoveIdentityCacheOnWebInteractor>(tag: _tag);
}
}