TF-3454 Download all attachments as ZIP

This commit is contained in:
DatDang
2025-02-07 14:38:53 +07:00
committed by Dat H. Pham
parent 636df94458
commit f66e1460e4
34 changed files with 1175 additions and 100 deletions
@@ -199,4 +199,24 @@ abstract class EmailRepository {
Future<String> sanitizeHtmlContent(
String htmlContent,
TransformConfiguration configuration);
Future<void> downloadAllAttachmentsForWeb(
AccountId accountId,
EmailId emailId,
String baseDownloadAllUrl,
String outputFileName,
AccountRequest accountRequest,
DownloadTaskId taskId,
StreamController<Either<Failure, Success>> onReceiveController,
{CancelToken? cancelToken}
);
Future<DownloadedResponse> exportAllAttachments(
AccountId accountId,
EmailId emailId,
String baseDownloadAllUrl,
String outputFileName,
AccountRequest accountRequest,
{CancelToken? cancelToken}
);
}
@@ -0,0 +1,51 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:model/download/download_task_id.dart';
import 'package:model/email/attachment.dart';
class StartDownloadAllAttachmentsForWeb extends UIState {
StartDownloadAllAttachmentsForWeb(this.taskId, this.attachment);
final DownloadTaskId taskId;
final Attachment attachment;
@override
List<Object> get props => [taskId, attachment];
}
class DownloadingAllAttachmentsForWeb extends LoadingState {
DownloadingAllAttachmentsForWeb(
this.taskId,
this.fileName,
this.progress,
this.downloaded,
this.total,
);
final DownloadTaskId taskId;
final String fileName;
final double progress;
final int downloaded;
final int total;
@override
List<Object?> get props => [taskId, fileName, progress, downloaded, total];
}
class DownloadAllAttachmentsForWebSuccess extends UIState {
DownloadAllAttachmentsForWebSuccess({required this.taskId});
final DownloadTaskId taskId;
@override
List<Object> get props => [taskId];
}
class DownloadAllAttachmentsForWebFailure extends FeatureFailure {
DownloadAllAttachmentsForWebFailure({super.exception, required this.taskId});
final DownloadTaskId taskId;
@override
List<Object> get props => [exception, taskId];
}
@@ -0,0 +1,18 @@
import 'package:core/data/network/download/downloaded_response.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
class ExportingAllAttachments extends LoadingState {}
class ExportAllAttachmentsSuccess extends UIState {
ExportAllAttachmentsSuccess(this.downloadedResponse);
final DownloadedResponse downloadedResponse;
@override
List<Object> get props => [downloadedResponse];
}
class ExportAllAttachmentsFailure extends FeatureFailure {
ExportAllAttachmentsFailure({super.exception});
}
@@ -0,0 +1,83 @@
import 'dart:async';
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:dio/dio.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/account/account_request.dart';
import 'package:model/account/authentication_type.dart';
import 'package:model/account/password.dart';
import 'package:model/download/download_task_id.dart';
import 'package:model/email/attachment.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/download_all_attachments_for_web_state.dart';
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
class DownloadAllAttachmentsForWebInteractor {
const DownloadAllAttachmentsForWebInteractor(
this._emailRepository,
this._accountRepository,
this._authenticationOIDCRepository,
this.credentialRepository,
);
final EmailRepository _emailRepository;
final AccountRepository _accountRepository;
final AuthenticationOIDCRepository _authenticationOIDCRepository;
final CredentialRepository credentialRepository;
Stream<Either<Failure, Success>> execute(
AccountId accountId,
EmailId emailId,
String baseDownloadAllUrl,
Attachment attachment,
DownloadTaskId taskId,
StreamController<Either<Failure, Success>> onReceiveController,
{CancelToken? cancelToken}
) async* {
try {
yield Right(StartDownloadAllAttachmentsForWeb(
taskId,
attachment,
));
onReceiveController.add(Right(StartDownloadAllAttachmentsForWeb(
taskId,
attachment,
)));
final currentAccount = await _accountRepository.getCurrentAccount();
AccountRequest accountRequest;
if (currentAccount.authenticationType == AuthenticationType.oidc) {
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
accountRequest = AccountRequest.withOidc(token: tokenOidc);
} else {
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
accountRequest = AccountRequest.withBasic(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
);
}
await _emailRepository.downloadAllAttachmentsForWeb(
accountId,
emailId,
baseDownloadAllUrl,
attachment.name!,
accountRequest,
taskId,
onReceiveController,
cancelToken: cancelToken
);
yield Right(DownloadAllAttachmentsForWebSuccess(taskId: taskId));
} catch (e) {
logError('DownloadAllAttachmentsForWebInteractor::execute():EXCEPTION: $e');
yield Left(DownloadAllAttachmentsForWebFailure(exception: e, taskId: taskId));
}
}
}
@@ -0,0 +1,68 @@
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:dio/dio.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:model/account/account_request.dart';
import 'package:model/account/authentication_type.dart';
import 'package:model/account/password.dart';
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
import 'package:tmail_ui_user/features/email/domain/state/export_all_attachments_state.dart';
import 'package:tmail_ui_user/features/login/domain/repository/account_repository.dart';
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart';
class ExportAllAttachmentsInteractor {
const ExportAllAttachmentsInteractor(
this._emailRepository,
this._accountRepository,
this._authenticationOIDCRepository,
this.credentialRepository,
);
final EmailRepository _emailRepository;
final AccountRepository _accountRepository;
final AuthenticationOIDCRepository _authenticationOIDCRepository;
final CredentialRepository credentialRepository;
Stream<Either<Failure, Success>> execute(
AccountId accountId,
EmailId emailId,
String baseDownloadAllUrl,
String outputFileName,
{CancelToken? cancelToken}
) async* {
try {
yield Right(ExportingAllAttachments());
final currentAccount = await _accountRepository.getCurrentAccount();
AccountRequest accountRequest;
if (currentAccount.authenticationType == AuthenticationType.oidc) {
final tokenOidc = await _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id);
accountRequest = AccountRequest.withOidc(token: tokenOidc);
} else {
final authenticationInfoCache = await credentialRepository.getAuthenticationInfoStored();
accountRequest = AccountRequest.withBasic(
userName: UserName(authenticationInfoCache.username),
password: Password(authenticationInfoCache.password),
);
}
final result = await _emailRepository.exportAllAttachments(
accountId,
emailId,
baseDownloadAllUrl,
outputFileName,
accountRequest,
cancelToken: cancelToken,
);
yield Right(ExportAllAttachmentsSuccess(result));
} catch (e) {
logError('ExportAllAttachmentsInteractor::execute():EXCEPTION: $e');
yield Left(ExportAllAttachmentsFailure(exception: e));
}
}
}