TF-2305 Fixed getUploadUri and getDownloadUri not working with Cyrus

This commit is contained in:
Florent Azavant
2025-01-17 11:36:14 +01:00
committed by Dat H. Pham
parent c3887b7705
commit 327af38fb0
13 changed files with 333 additions and 163 deletions
@@ -5,23 +5,20 @@ extension URIExtension on Uri {
Uri toQualifiedUrl({required Uri baseUrl}) { Uri toQualifiedUrl({required Uri baseUrl}) {
log('SessionUtils::toQualifiedUrl():baseUrl: $baseUrl | sourceUrl: $this'); log('SessionUtils::toQualifiedUrl():baseUrl: $baseUrl | sourceUrl: $this');
if (toString().startsWith(baseUrl.toString())) { if (hasOrigin) {
final qualifiedUrl = toString().removeLastSlashOfUrl(); final qualifiedUrl = toString();
log('SessionUtils::toQualifiedUrl():qualifiedUrl: $qualifiedUrl'); log('SessionUtils::toQualifiedUrl():qualifiedUrl: $qualifiedUrl');
return Uri.parse(qualifiedUrl); return Uri.parse(qualifiedUrl);
} else if (toString().isEmpty) {
log('SessionUtils::toQualifiedUrl():qualifiedUrl: $baseUrl');
return baseUrl;
} else { } else {
if (!hasOrigin) { final baseUrlValid = baseUrl.toString().removeLastSlashOfUrl();
final baseUrlValid = baseUrl.toString().removeLastSlashOfUrl(); final sourceUrlValid = toString().addFirstSlashOfUrl();
final sourceUrlValid = toString().addFirstSlashOfUrl().removeLastSlashOfUrl(); log('SessionUtils::toQualifiedUrl():baseUrlValid: $baseUrlValid | sourceUrlValid: $sourceUrlValid');
log('SessionUtils::toQualifiedUrl():baseUrlValid: $baseUrlValid | sourceUrlValid: $sourceUrlValid'); final qualifiedUrl = baseUrlValid + sourceUrlValid;
final qualifiedUrl = baseUrlValid + sourceUrlValid; log('SessionUtils::toQualifiedUrl():qualifiedUrl: $qualifiedUrl');
log('SessionUtils::toQualifiedUrl():qualifiedUrl: $qualifiedUrl'); return Uri.parse(qualifiedUrl);
return Uri.parse(qualifiedUrl);
} else {
final qualifiedUrl = toString().removeLastSlashOfUrl();
log('SessionUtils::toQualifiedUrl():qualifiedUrl: $qualifiedUrl');
return Uri.parse(qualifiedUrl);
}
} }
} }
@@ -16,11 +16,21 @@ void main() {
expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
}); });
test('convertToQualifiedUrl() should return qualified url when baseUrl is `https://domain.com` and sourceUrl is `https://domain.com/jmap/`', () async {
final baseUrl = Uri.parse('https://domain.com');
final sourceUrl = Uri.parse('https://domain.com/jmap/');
final qualifiedUrlExpected = Uri.parse('https://domain.com/jmap/');
final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl);
expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
});
test('convertToQualifiedUrl() should return qualified url when baseUrl is `https://domain.com` and sourceUrl is `/jmap/`', () async { test('convertToQualifiedUrl() should return qualified url when baseUrl is `https://domain.com` and sourceUrl is `/jmap/`', () async {
final baseUrl = Uri.parse('https://domain.com'); final baseUrl = Uri.parse('https://domain.com');
final sourceUrl = Uri.parse('/jmap/'); final sourceUrl = Uri.parse('/jmap/');
final qualifiedUrlExpected = Uri.parse('https://domain.com/jmap'); final qualifiedUrlExpected = Uri.parse('https://domain.com/jmap/');
final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl); final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl);
expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
@@ -50,7 +60,7 @@ void main() {
final baseUrl = Uri.parse('https://domain.com/jmap'); final baseUrl = Uri.parse('https://domain.com/jmap');
final sourceUrl = Uri.parse('/'); final sourceUrl = Uri.parse('/');
final qualifiedUrlExpected = Uri.parse('https://domain.com/jmap'); final qualifiedUrlExpected = Uri.parse('https://domain.com/jmap/');
final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl); final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl);
expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
@@ -70,7 +80,7 @@ void main() {
final baseUrl = Uri.parse('https://domain.com:2000/jmap'); final baseUrl = Uri.parse('https://domain.com:2000/jmap');
final sourceUrl = Uri.parse('https://domain.com:2001/jmap/'); final sourceUrl = Uri.parse('https://domain.com:2001/jmap/');
final qualifiedUrlExpected = Uri.parse('https://domain.com:2001/jmap'); final qualifiedUrlExpected = Uri.parse('https://domain.com:2001/jmap/');
final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl); final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl);
expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
@@ -86,7 +96,7 @@ void main() {
expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
}); });
test('convertToQualifiedUrl() should return qualified url when baseUrl is localhost and sourceUrl is `https://domain.com:2001/basiauth/jmap`', () async { test('convertToQualifiedUrl() should return qualified url when baseUrl is localhost and sourceUrl is `https://domain.com:2001/basicauth/jmap`', () async {
final baseUrl = Uri.parse('https://localhost:9080/basicauth'); final baseUrl = Uri.parse('https://localhost:9080/basicauth');
final sourceUrl = Uri.parse('https://domain.com:2001/basicauth/jmap'); final sourceUrl = Uri.parse('https://domain.com:2001/basicauth/jmap');
@@ -95,5 +105,15 @@ void main() {
expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
}); });
test('convertToQualifiedUrl() should return qualified url when baseUrl is localhost and sourceUrl is `https://domain.com:2001/basicauth/jmap/`', () async {
final baseUrl = Uri.parse('https://localhost:9080/basicauth');
final sourceUrl = Uri.parse('https://domain.com:2001/basicauth/jmap/');
final qualifiedUrlExpected = Uri.parse('https://domain.com:2001/basicauth/jmap/');
final qualifiedUrlResult = sourceUrl.toQualifiedUrl(baseUrl: baseUrl);
expect(qualifiedUrlResult, equals(qualifiedUrlExpected));
});
}); });
} }
@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io' hide HttpClient; import 'dart:io' hide HttpClient;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:core/utils/app_logger.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/http/http_client.dart'; import 'package:jmap_dart_client/http/http_client.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
@@ -142,33 +143,39 @@ mixin ScenarioUtilsMixin {
filePath: path, filePath: path,
fileSize: await file.length(), fileSize: await file.length(),
); );
final uploadUri = mailboxDashBoardController.sessionCurrent!.getUploadUri(
mailboxDashBoardController.accountId.value!,
jmapUrl: mailboxDashBoardController.dynamicUrlInterceptors.jmapUrl,
);
final uploadAttachmentInteractor = Get.find<UploadAttachmentInteractor>();
final uploadAttachmentState = await uploadAttachmentInteractor
.execute(fileInfo, uploadUri)
.last;
final attachment = await uploadAttachmentState.fold(
(failure) => null,
(success) async {
if (success is UploadAttachmentSuccess) {
final uploadAttachment = await success.uploadAttachment.progressState.last;
return uploadAttachment.fold(
(failure) => null,
(success) {
if (success is! SuccessAttachmentUploadState) return null;
return success.attachment; try {
}, final uploadUri = mailboxDashBoardController.sessionCurrent!.getUploadUri(
); mailboxDashBoardController.accountId.value!,
} jmapUrl: mailboxDashBoardController.dynamicUrlInterceptors.jmapUrl,
}, );
);
if (attachment != null) { final uploadAttachmentInteractor = Get.find<UploadAttachmentInteractor>();
attachments.add(attachment); final uploadAttachmentState = await uploadAttachmentInteractor
.execute(fileInfo, uploadUri)
.last;
final attachment = await uploadAttachmentState.fold(
(failure) => null,
(success) async {
if (success is UploadAttachmentSuccess) {
final uploadAttachment = await success.uploadAttachment.progressState.last;
return uploadAttachment.fold(
(failure) => null,
(success) {
if (success is! SuccessAttachmentUploadState) return null;
return success.attachment;
},
);
}
},
);
if (attachment != null) {
attachments.add(attachment);
}
} catch (e) {
logError('ScenarioUtilsMixin::uploadAttachments(): $e');
return attachments;
} }
} }
@@ -44,6 +44,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/restore_email_inlin
import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart';
import 'package:tmail_ui_user/features/composer/domain/state/upload_attachment_state.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart';
import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart';
@@ -709,8 +710,15 @@ class ComposerController extends BaseController
inlineImages: arguments.inlineImages); inlineImages: arguments.inlineImages);
final accountId = mailboxDashBoardController.accountId.value; final accountId = mailboxDashBoardController.accountId.value;
final downloadUrl = mailboxDashBoardController.sessionCurrent dynamic downloadUrl;
?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); try {
downloadUrl = mailboxDashBoardController.sessionCurrent
?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
} catch (e) {
logError('ComposerController::_initEmail(): $e');
downloadUrl = null;
}
if (accountId == null || downloadUrl == null) return; if (accountId == null || downloadUrl == null) return;
_getEmailContentFromSessionStorageBrowser( _getEmailContentFromSessionStorageBrowser(
htmlContent: arguments.emailContents ?? '', htmlContent: arguments.emailContents ?? '',
@@ -1226,15 +1234,21 @@ class ComposerController extends BaseController
); );
} }
void _uploadAttachmentsAction({required List<FileInfo> pickedFiles}) { void _uploadAttachmentsAction({required List<FileInfo> pickedFiles}) {
final session = mailboxDashBoardController.sessionCurrent; final session = mailboxDashBoardController.sessionCurrent;
final accountId = mailboxDashBoardController.accountId.value; final accountId = mailboxDashBoardController.accountId.value;
if (session != null && accountId != null) { if (session != null && accountId != null) {
final uploadUri = session.getUploadUri(accountId, jmapUrl: dynamicUrlInterceptors.jmapUrl); try {
uploadController.justUploadAttachmentsAction( final uploadUri = session.getUploadUri(accountId, jmapUrl: dynamicUrlInterceptors.jmapUrl);
uploadFiles: pickedFiles, uploadController.justUploadAttachmentsAction(
uploadUri: uploadUri, uploadFiles: pickedFiles,
); uploadUri: uploadUri,
);
} catch (e) {
log('ComposerController::_uploadAttachmentsAction: $e');
uploadController.consumeState(Stream.value(Left(UploadAttachmentFailure(e, pickedFiles[0]))));
}
} else { } else {
log('ComposerController::_uploadAttachmentsAction: SESSION OR ACCOUNT_ID is NULL'); log('ComposerController::_uploadAttachmentsAction: SESSION OR ACCOUNT_ID is NULL');
} }
@@ -1407,15 +1421,20 @@ class ComposerController extends BaseController
return; return;
} }
consumeState(_getEmailContentInteractor.execute( try {
session, consumeState(_getEmailContentInteractor.execute(
accountId, session,
emailId, accountId,
mailboxDashBoardController.baseDownloadUrl, emailId,
TransformConfiguration.forEditDraftsEmail(), mailboxDashBoardController.baseDownloadUrl,
additionalProperties: Properties({ TransformConfiguration.forEditDraftsEmail(),
IndividualHeaderIdentifier.identityHeader.value}), additionalProperties: Properties({
)); IndividualHeaderIdentifier.identityHeader.value}),
));
} catch (e) {
logError('ComposerController::_handleUploadInlineSuccess(): $e');
consumeState(Stream.value(Left(GetEmailContentFailure(e))));
}
} }
void _getEmailContentOffLineSuccess(GetEmailContentFromCacheSuccess success) { void _getEmailContentOffLineSuccess(GetEmailContentFromCacheSuccess success) {
@@ -1855,7 +1874,12 @@ class ComposerController extends BaseController
void _handleUploadInlineSuccess(SuccessAttachmentUploadState uploadState) { void _handleUploadInlineSuccess(SuccessAttachmentUploadState uploadState) {
uploadController.clearUploadInlineViewState(); uploadController.clearUploadInlineViewState();
final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); String? baseDownloadUrl;
try {
baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
} catch (e) {
logError('ComposerController::_handleUploadInlineSuccess(): $e');
}
final accountId = mailboxDashBoardController.accountId.value; final accountId = mailboxDashBoardController.accountId.value;
if (baseDownloadUrl != null && accountId != null) { if (baseDownloadUrl != null && accountId != null) {
@@ -1867,6 +1891,9 @@ class ComposerController extends BaseController
uploadState.fileInfo, uploadState.fileInfo,
maxWidth: maxWithEditor, maxWidth: maxWithEditor,
)); ));
} else {
log('ComposerController::_handleUploadInlineFailure(): baseDownloadUrl: $baseDownloadUrl, accountId: $accountId');
consumeState(Stream.value(Left(DownloadImageAsBase64Failure(e))));
} }
} }
@@ -0,0 +1,5 @@
import 'package:core/presentation/state/failure.dart';
class GetListDetailedEmailByIdFailure extends FeatureFailure {
GetListDetailedEmailByIdFailure({super.exception});
}
@@ -0,0 +1,6 @@
import 'package:core/presentation/state/failure.dart';
class PreviewPDFFileFailure extends FeatureFailure {
PreviewPDFFileFailure(dynamic exception) : super(exception: exception);
}
@@ -66,6 +66,7 @@ import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.
import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_email_by_blob_id_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/preview_email_from_eml_file_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/preview_pdf_file_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/print_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/print_email_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/send_receipt_to_sender_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/send_receipt_to_sender_state.dart';
import 'package:tmail_ui_user/features/email/domain/state/store_event_attendance_status_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/store_event_attendance_status_state.dart';
@@ -314,6 +315,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_handlePreviewEmailFromEMLFileFailure(failure); _handlePreviewEmailFromEMLFileFailure(failure);
} else if (failure is GetHtmlContentFromAttachmentFailure) { } else if (failure is GetHtmlContentFromAttachmentFailure) {
_handleGetHtmlContentFromAttachmentFailure(failure); _handleGetHtmlContentFromAttachmentFailure(failure);
} else if (failure is PreviewPDFFileFailure) {
_handlePreviewPDFFileFailure(failure);
} }
} }
@@ -530,18 +533,23 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
))); )));
} else { } else {
if (session != null && accountId != null) { if (session != null && accountId != null) {
final baseDownloadUrl = session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); try {
TransformConfiguration transformConfiguration = PlatformInfo.isWeb final baseDownloadUrl = session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
? TransformConfiguration.forPreviewEmailOnWeb() TransformConfiguration transformConfiguration = PlatformInfo.isWeb
: TransformConfiguration.forPreviewEmail(); ? TransformConfiguration.forPreviewEmailOnWeb()
: TransformConfiguration.forPreviewEmail();
consumeState(_getEmailContentInteractor.execute( consumeState(_getEmailContentInteractor.execute(
session!, session!,
accountId!, accountId!,
emailId, emailId,
baseDownloadUrl, baseDownloadUrl,
transformConfiguration transformConfiguration
)); ));
} catch (e) {
logError('SingleEmailController::_getEmailContentAction(): $e');
consumeState(Stream.value(Left(GetEmailContentFailure(e))));
}
} }
} }
} }
@@ -767,14 +775,19 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void _downloadAttachmentsAction(List<Attachment> attachments) { void _downloadAttachmentsAction(List<Attachment> attachments) {
if (accountId != null && session != null) { if (accountId != null && session != null) {
final baseDownloadUrl = session!.getDownloadUrl( try {
jmapUrl: dynamicUrlInterceptors.jmapUrl, final baseDownloadUrl = session!.getDownloadUrl(
); jmapUrl: dynamicUrlInterceptors.jmapUrl,
consumeState(_downloadAttachmentsInteractor.execute( );
attachments, consumeState(_downloadAttachmentsInteractor.execute(
accountId!, attachments,
baseDownloadUrl, accountId!,
)); baseDownloadUrl,
));
} catch (e) {
logError('SingleEmailController::_downloadAttachmentsAction(): $e');
consumeState(Stream.value(Left(DownloadAttachmentsFailure(e))));
}
} }
} }
@@ -821,15 +834,20 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void _exportAttachmentAction(Attachment attachment, CancelToken cancelToken) { void _exportAttachmentAction(Attachment attachment, CancelToken cancelToken) {
if (accountId != null && session != null) { if (accountId != null && session != null) {
final baseDownloadUrl = session!.getDownloadUrl( try {
jmapUrl: dynamicUrlInterceptors.jmapUrl, final baseDownloadUrl = session!.getDownloadUrl(
); jmapUrl: dynamicUrlInterceptors.jmapUrl,
consumeState(_exportAttachmentInteractor.execute( );
attachment, consumeState(_exportAttachmentInteractor.execute(
accountId!, attachment,
baseDownloadUrl, accountId!,
cancelToken, baseDownloadUrl,
)); cancelToken,
));
} catch (e) {
logError('SingleEmailController::_exportAttachmentAction(): $e');
consumeState(Stream.value(Left(ExportAttachmentFailure(e))));
}
} }
} }
@@ -873,16 +891,21 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void downloadAttachmentForWeb(Attachment attachment) { void downloadAttachmentForWeb(Attachment attachment) {
if (accountId != null && session != null) { if (accountId != null && session != null) {
final baseDownloadUrl = session!.getDownloadUrl(
jmapUrl: dynamicUrlInterceptors.jmapUrl,
);
final generateTaskId = DownloadTaskId(uuid.v4()); final generateTaskId = DownloadTaskId(uuid.v4());
consumeState(_downloadAttachmentForWebInteractor.execute( try {
generateTaskId, final baseDownloadUrl = session!.getDownloadUrl(
attachment, jmapUrl: dynamicUrlInterceptors.jmapUrl,
accountId!, );
baseDownloadUrl, consumeState(_downloadAttachmentForWebInteractor.execute(
_downloadProgressStateController)); generateTaskId,
attachment,
accountId!,
baseDownloadUrl,
_downloadProgressStateController));
} catch (e) {
logError('SingleEmailController::downloadAttachmentForWeb(): $e');
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(attachment: attachment, taskId: generateTaskId, exception: e))));
}
} else { } else {
consumeState(Stream.value( consumeState(Stream.value(
Left(DownloadAttachmentForWebFailure( Left(DownloadAttachmentForWebFailure(
@@ -2002,8 +2025,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
Attachment attachment, Attachment attachment,
) { ) {
final accountId = mailboxDashBoardController.accountId.value; final accountId = mailboxDashBoardController.accountId.value;
final downloadUrl = mailboxDashBoardController.sessionCurrent dynamic downloadUrl;
try {
downloadUrl = mailboxDashBoardController.sessionCurrent
?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl); ?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl);
} catch (e) {
logError('SingleEmailController::_getEmailContentAction(): $e');
downloadUrl = null;
}
final blobId = attachment.blobId; final blobId = attachment.blobId;
if (accountId == null || downloadUrl == null || blobId == null) { if (accountId == null || downloadUrl == null || blobId == null) {
@@ -2030,24 +2059,30 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
AppLocalizations.of(context).noPreviewAvailable); AppLocalizations.of(context).noPreviewAvailable);
return; return;
} }
final downloadUrl = session!.getDownloadUrl(
jmapUrl: dynamicUrlInterceptors.jmapUrl,
);
await Get.generalDialog( try {
barrierColor: Colors.black.withOpacity(0.8), final downloadUrl = session!.getDownloadUrl(
pageBuilder: (_, __, ___) { jmapUrl: dynamicUrlInterceptors.jmapUrl,
return PointerInterceptor( );
child: PDFViewer(
attachment: attachment, await Get.generalDialog(
accountId: accountId!, barrierColor: Colors.black.withOpacity(0.8),
downloadUrl: downloadUrl, pageBuilder: (_, __, ___) {
downloadAction: _downloadPDFFile, return PointerInterceptor(
printAction: _printPDFFile, child: PDFViewer(
) attachment: attachment,
); accountId: accountId!,
}, downloadUrl: downloadUrl,
); downloadAction: _downloadPDFFile,
printAction: _printPDFFile,
)
);
},
);
} catch (e) {
logError('SingleEmailController::previewPDFFileAction(): $e');
consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(e))));
}
} }
void previewEMLFileAction(Id? blobId, AppLocalizations appLocalizations) { void previewEMLFileAction(Id? blobId, AppLocalizations appLocalizations) {
@@ -2085,17 +2120,22 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
return; return;
} }
consumeState(_previewEmailFromEmlFileInteractor.execute( try {
PreviewEmailEMLRequest( consumeState(_previewEmailFromEmlFileInteractor.execute(
accountId: accountId!, PreviewEmailEMLRequest(
userName: userName!, accountId: accountId!,
blobId: success.blobId, userName: userName!,
email: success.email, blobId: success.blobId,
locale: Localizations.localeOf(currentContext!), email: success.email,
appLocalizations: AppLocalizations.of(currentContext!), locale: Localizations.localeOf(currentContext!),
baseDownloadUrl: session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl), appLocalizations: AppLocalizations.of(currentContext!),
), baseDownloadUrl: session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl),
)); ),
));
} catch (e) {
logError('SingleEmailController::_handleParseEmailByBlobIdSuccess(): $e');
consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(e))));
}
} }
void _handleParseEmailByBlobIdFailure(ParseEmailByBlobIdFailure failure) { void _handleParseEmailByBlobIdFailure(ParseEmailByBlobIdFailure failure) {
@@ -2103,6 +2143,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
toastManager.showMessageFailure(failure); toastManager.showMessageFailure(failure);
} }
void _handlePreviewPDFFileFailure(PreviewPDFFileFailure failure) {
SmartDialog.dismiss();
toastManager.showMessageFailure(failure);
}
void _handlePreviewEmailFromEMLFileFailure(PreviewEmailFromEmlFileFailure failure) { void _handlePreviewEmailFromEMLFileFailure(PreviewEmailFromEmlFileFailure failure) {
SmartDialog.dismiss(); SmartDialog.dismiss();
toastManager.showMessageFailure(failure); toastManager.showMessageFailure(failure);
@@ -267,18 +267,23 @@ class EmailPreviewerController extends ReloadableController {
return; return;
} }
consumeState(_previewEmailFromEmlFileInteractor.execute( try {
PreviewEmailEMLRequest( consumeState(_previewEmailFromEmlFileInteractor.execute(
accountId: _accountId!, PreviewEmailEMLRequest(
userName: _session!.username, accountId: _accountId!,
blobId: success.blobId, userName: _session!.username,
email: success.email, blobId: success.blobId,
locale: Localizations.localeOf(currentContext!), email: success.email,
appLocalizations: AppLocalizations.of(currentContext!), locale: Localizations.localeOf(currentContext!),
baseDownloadUrl: _session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl), appLocalizations: AppLocalizations.of(currentContext!),
isShared: false, baseDownloadUrl: _session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl),
), isShared: false,
)); ),
));
} catch (e) {
logError('EmailPreviewerController::_handleParseEmailByBlobIdSuccess(): $e');
consumeState(Stream.value(Left(PreviewEmailFromEmlFileFailure(e))));
}
} }
void _updateWindowBrowserTitle(String title) { void _updateWindowBrowserTitle(String title) {
@@ -308,14 +313,22 @@ class EmailPreviewerController extends ReloadableController {
} }
void _startDownloadAttachment(Attachment attachment) { void _startDownloadAttachment(Attachment attachment) {
_downloadInteractorStreamSubscription = _downloadAttachmentForWebInteractor try {
.execute( _downloadInteractorStreamSubscription = _downloadAttachmentForWebInteractor
attachment.downloadTaskId, .execute(
attachment, attachment.downloadTaskId,
_accountId!, attachment,
_session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl), _accountId!,
_downloadAttachmentStreamController!) _session!.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl),
.listen(_handleDownloadAttachmentViewState); _downloadAttachmentStreamController!)
.listen(_handleDownloadAttachmentViewState);
} catch (e) {
logError('EmailPreviewerController::_handleParseEmailByBlobIdSuccess(): $e');
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(
attachment: attachment,
taskId: attachment.downloadTaskId,
exception: e))));
}
} }
void _initialDownloadAttachmentStreamListener() { void _initialDownloadAttachmentStreamListener() {
@@ -2755,7 +2755,14 @@ class MailboxDashBoardController extends ReloadableController
dispatchAction(SelectionAllEmailAction()); dispatchAction(SelectionAllEmailAction());
} }
String get baseDownloadUrl => sessionCurrent?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl) ?? ''; String get baseDownloadUrl {
try {
return sessionCurrent?.getDownloadUrl(jmapUrl: dynamicUrlInterceptors.jmapUrl) ?? '';
} catch (e) {
logError('MailboxDashboardController::baseDownloadUrl(): $e');
return '';
}
}
void redirectToInboxAction() { void redirectToInboxAction() {
log('MailboxDashBoardController::redirectToInboxAction:'); log('MailboxDashBoardController::redirectToInboxAction:');
@@ -9,6 +9,7 @@ import 'package:core/utils/file_utils.dart';
import 'package:core/utils/platform_info.dart'; import 'package:core/utils/platform_info.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart';
@@ -126,6 +127,8 @@ class PublicAssetController extends BaseController {
_handleCreatePublicAssetFailureState(); _handleCreatePublicAssetFailureState();
} else if (failure is PublicAssetOverQuotaFailureState) { } else if (failure is PublicAssetOverQuotaFailureState) {
_handlePublicAssetOverQuotaFailureState(failure); _handlePublicAssetOverQuotaFailureState(failure);
} else if (failure is UploadAttachmentFailure) {
_handleUploadAttachmentFailure(failure);
} }
} }
@@ -156,6 +159,21 @@ class PublicAssetController extends BaseController {
} }
} }
void _handleUploadAttachmentFailure(UploadAttachmentFailure failure) {
if (currentContext != null && currentOverlayContext != null) {
appToast.showToastErrorMessage(
currentOverlayContext!,
failure.fileInfo.isInline == true
? AppLocalizations.of(currentContext!).thisImageCannotBeAdded
: AppLocalizations.of(currentContext!).can_not_upload_this_file_as_attachments,
leadingSVGIconColor: Colors.white,
leadingSVGIcon: failure.fileInfo.isInline == true
? imagePaths.icInsertImage
: imagePaths.icAttachment
);
}
}
Future<void> _handleUploadAttachmentSuccess(UploadAttachmentSuccess success) async { Future<void> _handleUploadAttachmentSuccess(UploadAttachmentSuccess success) async {
await _publicAssetStreamGroup.add(success.uploadAttachment.progressState); await _publicAssetStreamGroup.add(success.uploadAttachment.progressState);
} }
@@ -206,8 +224,13 @@ class PublicAssetController extends BaseController {
if (session == null || accountId == null) return; if (session == null || accountId == null) return;
final fileInfo = platformFile.toFileInfo(); final fileInfo = platformFile.toFileInfo();
final uploadUri = session!.getUploadUri(accountId!, jmapUrl: dynamicUrlInterceptors.jmapUrl); try {
consumeState(_uploadAttachmentInteractor.execute(fileInfo, uploadUri)); final uploadUri = session!.getUploadUri(accountId!, jmapUrl: dynamicUrlInterceptors.jmapUrl);
consumeState(_uploadAttachmentInteractor.execute(fileInfo, uploadUri));
} catch (e) {
log('PublicAssetController::_uploadFileToBlobAction: $e');
consumeState(Stream.value(Left(UploadAttachmentFailure(e, fileInfo))));
}
} }
void discardChanges() { void discardChanges() {
@@ -4,6 +4,7 @@ import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart'; import 'package:core/utils/app_logger.dart';
import 'package:core/utils/platform_info.dart'; import 'package:core/utils/platform_info.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.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/session/session.dart';
@@ -334,13 +335,18 @@ class EmailChangeListener extends ChangeListener {
if (_getListDetailedEmailByIdInteractor != null && if (_getListDetailedEmailByIdInteractor != null &&
_dynamicUrlInterceptors != null && _dynamicUrlInterceptors != null &&
session != null) { session != null) {
final baseDownloadUrl = session.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors!.jmapUrl); try {
consumeState(_getListDetailedEmailByIdInteractor!.execute( final baseDownloadUrl = session.getDownloadUrl(jmapUrl: _dynamicUrlInterceptors!.jmapUrl);
session, consumeState(_getListDetailedEmailByIdInteractor!.execute(
accountId, session,
emailIds, accountId,
baseDownloadUrl emailIds,
)); baseDownloadUrl
));
} catch (e) {
logError('EmailChangeListener::_getListDetailedEmailByIdAction(): $e');
consumeState(Stream.value(Left(GetDetailedEmailByIdFailure(e))));
}
} }
} }
@@ -0,0 +1 @@
class UnknownUriException implements Exception {}
+19 -6
View File
@@ -9,15 +9,22 @@ import 'package:jmap_dart_client/jmap/core/capability/capability_properties.dart
import 'package:jmap_dart_client/jmap/core/capability/empty_capability.dart'; import 'package:jmap_dart_client/jmap/core/capability/empty_capability.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:model/error_type_handler/account_exception.dart'; import 'package:model/error_type_handler/account_exception.dart';
import 'package:model/error_type_handler/unknown_uri_exception.dart';
import 'package:model/model.dart'; import 'package:model/model.dart';
import 'package:uri/uri.dart'; import 'package:uri/uri.dart';
extension SessionExtension on Session { extension SessionExtension on Session {
String getDownloadUrl({String? jmapUrl}) { String getDownloadUrl({String? jmapUrl}) {
final downloadUrlValid = jmapUrl != null final Uri downloadUrlValid;
? downloadUrl.toQualifiedUrl(baseUrl: Uri.parse(jmapUrl)) if (jmapUrl != null) {
: downloadUrl; downloadUrlValid = downloadUrl.toQualifiedUrl(baseUrl: Uri.parse(jmapUrl));
} else if (downloadUrl.hasOrigin) {
downloadUrlValid = downloadUrl;
} else {
throw UnknownUriException();
}
var baseUrl = '${downloadUrlValid.origin}${downloadUrlValid.path}?${downloadUrlValid.query}'; var baseUrl = '${downloadUrlValid.origin}${downloadUrlValid.path}?${downloadUrlValid.query}';
if (baseUrl.endsWith('/')) { if (baseUrl.endsWith('/')) {
baseUrl = baseUrl.substring(0, baseUrl.length - 1); baseUrl = baseUrl.substring(0, baseUrl.length - 1);
@@ -27,9 +34,15 @@ extension SessionExtension on Session {
} }
Uri getUploadUri(AccountId accountId, {String? jmapUrl}) { Uri getUploadUri(AccountId accountId, {String? jmapUrl}) {
final uploadUrlValid = jmapUrl != null final Uri uploadUrlValid;
? uploadUrl.toQualifiedUrl(baseUrl: Uri.parse(jmapUrl)) if (jmapUrl != null) {
: uploadUrl; uploadUrlValid = uploadUrl.toQualifiedUrl(baseUrl: Uri.parse(jmapUrl));
} else if (uploadUrl.hasOrigin) {
uploadUrlValid = uploadUrl;
} else {
throw UnknownUriException();
}
final baseUrl = '${uploadUrlValid.origin}${uploadUrlValid.path}'; final baseUrl = '${uploadUrlValid.origin}${uploadUrlValid.path}';
final uploadUriTemplate = UriTemplate(Uri.decodeFull(baseUrl)); final uploadUriTemplate = UriTemplate(Uri.decodeFull(baseUrl));
final uploadUri = uploadUriTemplate.expand({ final uploadUri = uploadUriTemplate.expand({