TF-3767 Clean up recent searches whenever re-login and exceeds limit

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-06-11 12:59:13 +07:00
committed by Dat H. Pham
parent a02435c9f5
commit 6fef6190e0
13 changed files with 136 additions and 61 deletions
@@ -1,4 +1,5 @@
import 'package:core/utils/app_logger.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';
@@ -18,16 +19,27 @@ class RecentSearchCacheManager {
RecentSearchCacheManager(this._recentSearchCacheClient);
Future<void> clean(RecentSearchCleanupRule cleanupRule) async {
final listRecentSearchCache = await _recentSearchCacheClient.getAll();
listRecentSearchCache.sortByCreationDate();
final nestedKey = TupleKey(
cleanupRule.accountId.asString,
cleanupRule.userName.value,
).encodeKey;
if (listRecentSearchCache.length > cleanupRule.storageLimit) {
final newListKeyRecent = listRecentSearchCache
.sublist(cleanupRule.storageLimit)
.map((recent) => recent.value)
.toList();
await _recentSearchCacheClient.deleteMultipleItem(newListKeyRecent);
}
final listRecentSearchCache = await _recentSearchCacheClient
.getListByNestedKey(nestedKey);
listRecentSearchCache.sortByCreationDate();
if (listRecentSearchCache.length > cleanupRule.storageLimit) {
final newListKeyRecent = listRecentSearchCache
.sublist(cleanupRule.storageLimit)
.map((recent) => recent.toRecentSearch().generateTupleKey(
cleanupRule.accountId,
cleanupRule.userName,
))
.toList();
log('RecentSearchCacheManager::clean: list recent to delete $newListKeyRecent');
await _recentSearchCacheClient.deleteMultipleItem(newListKeyRecent);
}
}
Future<void> saveRecentSearch(
@@ -76,6 +88,10 @@ class RecentSearchCacheManager {
? listRecentSearch.sublist(0, newLimit)
: listRecentSearch;
for (var recentSearch in newListRecentSearch) {
log('RecentSearchCacheManager::getAllLatest: Recent search: ${recentSearch.toString()}');
}
return newListRecentSearch;
}
@@ -1,13 +1,19 @@
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/cleanup/domain/model/cleanup_rule.dart';
class RecentSearchCleanupRule extends CleanupRule {
final int storageLimit;
final AccountId accountId;
final UserName userName;
RecentSearchCleanupRule(
{this.storageLimit = 10}
this.accountId,
this.userName,
{this.storageLimit = 10}
) : super();
@override
List<Object?> get props => [storageLimit];
List<Object?> get props => [accountId, userName, storageLimit];
}
@@ -1,6 +1,8 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class CleanupRecentSearchCacheLoading extends LoadingState {}
class CleanupRecentSearchCacheSuccess extends UIState {}
class CleanupRecentSearchCacheFailure extends FeatureFailure {
@@ -1,4 +1,5 @@
import 'package:core/core.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:tmail_ui_user/features/cleanup/domain/model/recent_search_cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/repository/cleanup_repository.dart';
@@ -9,13 +10,13 @@ class CleanupRecentSearchCacheInteractor {
CleanupRecentSearchCacheInteractor(this.cleanupRepository);
Future<Either<Failure, Success>> execute(RecentSearchCleanupRule cleanupRule) async {
Stream<Either<Failure, Success>> execute(RecentSearchCleanupRule cleanupRule) async* {
try {
yield Right<Failure, Success>(CleanupRecentSearchCacheLoading());
await cleanupRepository.cleanRecentSearchCache(cleanupRule);
log('CleanupRecentSearchCacheInteractor::execute(): SUCCESS');
return Right<Failure, Success>(CleanupRecentSearchCacheSuccess());
yield Right<Failure, Success>(CleanupRecentSearchCacheSuccess());
} catch (e) {
return Left(CleanupRecentSearchCacheFailure(e));
yield Left(CleanupRecentSearchCacheFailure(e));
}
}
}
@@ -0,0 +1,53 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
import 'package:tmail_ui_user/features/cleanup/data/datasource/cleanup_datasource.dart';
import 'package:tmail_ui_user/features/cleanup/data/datasource_impl/cleanup_datasource_impl.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_search_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/repository/cleanup_repository_impl.dart';
import 'package:tmail_ui_user/features/cleanup/domain/repository/cleanup_repository.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
class CleanupBindings extends InteractorsBindings {
@override
void bindingsDataSource() {
Get.lazyPut<CleanupDataSource>(() => Get.find<CleanupDataSourceImpl>());
}
@override
void bindingsDataSourceImpl() {
Get.lazyPut(() => CleanupDataSourceImpl(
Get.find<EmailCacheManager>(),
Get.find<RecentSearchCacheManager>(),
Get.find<RecentLoginUrlCacheManager>(),
Get.find<RecentLoginUsernameCacheManager>(),
Get.find<CacheExceptionThrower>(),
));
}
@override
void bindingsInteractor() {
Get.lazyPut(() => CleanupEmailCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentSearchCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentLoginUrlCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentLoginUsernameCacheInteractor(Get.find<CleanupRepository>()));
}
@override
void bindingsRepository() {
Get.lazyPut<CleanupRepository>(() => Get.find<CleanupRepositoryImpl>());
}
@override
void bindingsRepositoryImpl() {
Get.lazyPut(() => CleanupRepositoryImpl(Get.find<CleanupDataSource>()));
}
}
@@ -1,21 +1,12 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/base_bindings.dart';
import 'package:tmail_ui_user/features/cleanup/data/datasource/cleanup_datasource.dart';
import 'package:tmail_ui_user/features/cleanup/data/datasource_impl/cleanup_datasource_impl.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_url_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_login_username_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_search_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/repository/cleanup_repository_impl.dart';
import 'package:tmail_ui_user/features/cleanup/domain/repository/cleanup_repository.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/presentation/cleanup_bindings.dart';
import 'package:tmail_ui_user/features/home/presentation/home_controller.dart';
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/check_oidc_is_available_interactor.dart';
import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
import 'package:tmail_ui_user/main/utils/email_receive_manager.dart';
class HomeBindings extends BaseBindings {
@@ -25,44 +16,26 @@ class HomeBindings extends BaseBindings {
Get.lazyPut(() => HomeController(
Get.find<CleanupEmailCacheInteractor>(),
Get.find<EmailReceiveManager>(),
Get.find<CleanupRecentSearchCacheInteractor>(),
Get.find<CleanupRecentLoginUrlCacheInteractor>(),
Get.find<CleanupRecentLoginUsernameCacheInteractor>(),
));
}
@override
void bindingsDataSource() {
Get.lazyPut<CleanupDataSource>(() => Get.find<CleanupDataSourceImpl>());
}
void bindingsDataSource() {}
@override
void bindingsDataSourceImpl() {
Get.lazyPut(() => CleanupDataSourceImpl(
Get.find<EmailCacheManager>(),
Get.find<RecentSearchCacheManager>(),
Get.find<RecentLoginUrlCacheManager>(),
Get.find<RecentLoginUsernameCacheManager>(),
Get.find<CacheExceptionThrower>(),
));
}
void bindingsDataSourceImpl() {}
@override
void bindingsInteractor() {
Get.lazyPut(() => CleanupEmailCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentSearchCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentLoginUrlCacheInteractor(Get.find<CleanupRepository>()));
Get.lazyPut(() => CleanupRecentLoginUsernameCacheInteractor(Get.find<CleanupRepository>()));
CleanupBindings().dependencies();
Get.lazyPut(() => CheckOIDCIsAvailableInteractor(Get.find<AuthenticationOIDCRepository>()));
}
@override
void bindingsRepository() {
Get.lazyPut<CleanupRepository>(() => Get.find<CleanupRepositoryImpl>());
}
void bindingsRepository() {}
@override
void bindingsRepositoryImpl() {
Get.lazyPut(() => CleanupRepositoryImpl(Get.find<CleanupDataSource>()));
}
void bindingsRepositoryImpl() {}
}
@@ -15,11 +15,9 @@ import 'package:tmail_ui_user/features/cleanup/domain/model/cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/model/email_cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/model/recent_login_url_cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/model/recent_login_username_cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/model/recent_search_cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/home/domain/state/auto_sign_in_via_deep_link_state.dart';
import 'package:tmail_ui_user/features/home/domain/state/get_session_state.dart';
import 'package:tmail_ui_user/features/login/domain/exceptions/logout_exception.dart';
@@ -39,7 +37,6 @@ import 'package:tmail_ui_user/main/utils/ios_notification_manager.dart';
class HomeController extends ReloadableController {
final CleanupEmailCacheInteractor _cleanupEmailCacheInteractor;
final EmailReceiveManager _emailReceiveManager;
final CleanupRecentSearchCacheInteractor _cleanupRecentSearchCacheInteractor;
final CleanupRecentLoginUrlCacheInteractor _cleanupRecentLoginUrlCacheInteractor;
final CleanupRecentLoginUsernameCacheInteractor _cleanupRecentLoginUsernameCacheInteractor;
@@ -49,7 +46,6 @@ class HomeController extends ReloadableController {
HomeController(
this._cleanupEmailCacheInteractor,
this._emailReceiveManager,
this._cleanupRecentSearchCacheInteractor,
this._cleanupRecentLoginUrlCacheInteractor,
this._cleanupRecentLoginUsernameCacheInteractor,
);
@@ -107,7 +103,6 @@ class HomeController extends ReloadableController {
await Future.wait([
_cleanupEmailCacheInteractor.execute(EmailCleanupRule(Duration.defaultCacheInternal)),
_cleanupRecentSearchCacheInteractor.execute(RecentSearchCleanupRule()),
_cleanupRecentLoginUrlCacheInteractor.execute(RecentLoginUrlCleanupRule()),
_cleanupRecentLoginUsernameCacheInteractor.execute(RecentLoginUsernameCleanupRule()),
], eagerError: true).then((_) => getAuthenticatedAccountAction());
@@ -42,7 +42,10 @@ extension ListRecentSearchCacheExtension on List<RecentSearchCache> {
void sortByCreationDate() {
sort((recentSearch1, recentSearch2) {
return recentSearch1.creationDate.compareToSort(recentSearch1.creationDate, false);
return recentSearch1.creationDate.compareToSort(
recentSearch2.creationDate,
false,
);
});
}
}
@@ -6,7 +6,10 @@ extension ListRecentSearchExtension on List<RecentSearch> {
void sortByCreationDate() {
sort((recentSearch1, recentSearch2) {
return recentSearch1.creationDate.compareToSort(recentSearch1.creationDate, false);
return recentSearch1.creationDate.compareToSort(
recentSearch2.creationDate,
false,
);
});
}
}
@@ -11,6 +11,7 @@ import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/caching/utils/local_storage_manager.dart';
import 'package:tmail_ui_user/features/caching/utils/session_storage_manager.dart';
import 'package:tmail_ui_user/features/cleanup/data/local/recent_search_cache_manager.dart';
import 'package:tmail_ui_user/features/cleanup/presentation/cleanup_bindings.dart';
import 'package:tmail_ui_user/features/composer/data/repository/contact_repository_impl.dart';
import 'package:tmail_ui_user/features/composer/domain/repository/contact_repository.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
@@ -144,6 +145,7 @@ class MailboxDashBoardBindings extends BaseBindings {
@override
void dependencies() {
CleanupBindings().dependencies();
super.dependencies();
SendingQueueBindings().dependencies();
MailboxBindings().dependencies();
@@ -102,6 +102,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/download/download_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart' as search;
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/cleanup_recent_search_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/delete_emails_in_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_clear_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_filter_for_folder.dart';
@@ -781,6 +782,7 @@ class MailboxDashBoardController extends ReloadableController
spamReportController.getSpamReportStateAction();
_getAllIdentities();
getServerSetting();
cleanupRecentSearch();
if (PlatformInfo.isMobile) {
getAllSendingEmails();
@@ -0,0 +1,24 @@
import 'package:core/utils/app_logger.dart';
import 'package:tmail_ui_user/features/cleanup/domain/model/recent_search_cleanup_rule.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
extension CleanupRecentSearchExtension on MailboxDashBoardController {
void cleanupRecentSearch() {
final cleanupRecentSearchCacheInteractor =
getBinding<CleanupRecentSearchCacheInteractor>();
final accountId = this.accountId.value;
final username = sessionCurrent?.username;
if (accountId == null || username == null || cleanupRecentSearchCacheInteractor == null) {
logError('CleanupRecentSearchExtension::cleanupRecentSearch: accountId == null || username == null || cleanupRecentSearchCacheInteractor == null');
return;
}
consumeState(cleanupRecentSearchCacheInteractor.execute(
RecentSearchCleanupRule(accountId, username),
));
}
}
@@ -15,7 +15,6 @@ import 'package:tmail_ui_user/features/caching/caching_manager.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_email_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_url_cache_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_login_username_interactor.dart';
import 'package:tmail_ui_user/features/cleanup/domain/usecases/cleanup_recent_search_cache_interactor.dart';
import 'package:tmail_ui_user/features/home/domain/usecases/get_session_interactor.dart';
import 'package:tmail_ui_user/features/home/presentation/home_controller.dart';
import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart';
@@ -45,7 +44,6 @@ import 'home_controller_test.mocks.dart';
MockSpec<ResponsiveUtils>(),
MockSpec<Uuid>(),
MockSpec<CleanupEmailCacheInteractor>(),
MockSpec<CleanupRecentSearchCacheInteractor>(),
MockSpec<CleanupRecentLoginUrlCacheInteractor>(),
MockSpec<CleanupRecentLoginUsernameCacheInteractor>(),
MockSpec<EmailReceiveManager>(),
@@ -64,7 +62,6 @@ void main() {
late HomeController homeController;
late MockCleanupEmailCacheInteractor cleanupEmailCacheInteractor;
late MockEmailReceiveManager emailReceiveManager;
late MockCleanupRecentSearchCacheInteractor cleanupRecentSearchCacheInteractor;
late MockCleanupRecentLoginUrlCacheInteractor cleanupRecentLoginUrlCacheInteractor;
late MockCleanupRecentLoginUsernameCacheInteractor cleanupRecentLoginUsernameCacheInteractor;
@@ -90,7 +87,6 @@ void main() {
setUpAll(() {
cleanupEmailCacheInteractor = MockCleanupEmailCacheInteractor();
emailReceiveManager = MockEmailReceiveManager();
cleanupRecentSearchCacheInteractor = MockCleanupRecentSearchCacheInteractor();
cleanupRecentLoginUrlCacheInteractor = MockCleanupRecentLoginUrlCacheInteractor();
cleanupRecentLoginUsernameCacheInteractor = MockCleanupRecentLoginUsernameCacheInteractor();
@@ -142,7 +138,6 @@ void main() {
homeController = HomeController(
cleanupEmailCacheInteractor,
emailReceiveManager,
cleanupRecentSearchCacheInteractor,
cleanupRecentLoginUrlCacheInteractor,
cleanupRecentLoginUsernameCacheInteractor
);