import 'dart:async'; import 'dart:convert'; import 'dart:io' hide HttpClient; import 'package:collection/collection.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; import 'package:flutter/widgets.dart'; import 'package:get/get.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/id.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/jmap_request.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/set/set_email_method.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:labels/extensions/list_label_extension.dart'; import 'package:model/model.dart'; import 'package:path_provider/path_provider.dart'; import 'package:patrol/patrol.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_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/upload_attachment_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_bindings.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_identity_request.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_default_identity_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_identity_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_interactors_bindings.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart'; import 'package:tmail_ui_user/features/upload/domain/state/attachment_upload_state.dart'; import 'package:tmail_ui_user/main/error/capability_validator.dart'; import 'package:uuid/uuid.dart'; import '../models/provisioning_email.dart'; import '../models/provisioning_identity.dart'; import '../resources/test_images.dart'; mixin ScenarioUtilsMixin { Future provisionEmail( List provisioningEmails, { bool refreshEmailView = true, bool requestReadReceipt = true, Role? folderLocationRole, }) async { ComposerBindings().dependencies(); final mailboxDashBoardController = Get.find(); final createNewAndSendEmailInteractor = Get.find(); final threadController = Get.find(); final identity = await getIdentity(); if (identity == null) return; // Provision emails await Future.wait(provisioningEmails.map((provisioningEmail) async { final attachments = await uploadAttachments(provisioningEmail.attachmentPaths); // Create and send email return await createNewAndSendEmailInteractor .execute( createEmailRequest: CreateEmailRequest( session: mailboxDashBoardController.sessionCurrent!, accountId: mailboxDashBoardController.accountId.value!, emailActionType: EmailActionType.compose, ownEmailAddress: mailboxDashBoardController.ownEmailAddress.value, subject: provisioningEmail.subject, emailContent: provisioningEmail.content, toRecipients: {EmailAddress(null, provisioningEmail.toEmail)}, outboxMailboxId: mailboxDashBoardController.outboxMailbox?.mailboxId, sentMailboxId: folderLocationRole != null ? mailboxDashBoardController .mapDefaultMailboxIdByRole[folderLocationRole] : mailboxDashBoardController .mapDefaultMailboxIdByRole[PresentationMailbox.roleSent], identity: identity, attachments: attachments, hasRequestReadReceipt: requestReadReceipt, keywords: provisioningEmail.labels.keywords, ), ) .last; })); // Refresh view after provisioning emails if (refreshEmailView) { threadController.refreshAllEmail(); } ComposerBindings().dispose(); } Future simulateUpdateFlagsOfEmailsWithSubjectsFromOutsideCurrentClient({ required List subjects, bool? isRead, bool? isStar, }) async { final mailboxDashBoardController = Get.find(); final emails = mailboxDashBoardController.emailsInCurrentMailbox .where( (presentationEmail) => subjects.contains(presentationEmail.subject)) .toList(); final session = mailboxDashBoardController.sessionCurrent; final accountId = mailboxDashBoardController.accountId.value; if (session == null || accountId == null) return; final requestBuilder = JmapRequestBuilder( Get.find(), ProcessingInvocation(), ); final capabilities = {}; // Mark as read/unread if (isRead != null) { final markEmailAsReadMethod = SetEmailMethod(accountId) ..addUpdates(emails.listEmailIds.generateMapUpdateObjectMarkAsRead( isRead ? ReadActions.markAsRead : ReadActions.markAsUnread)); requestBuilder.invocation(markEmailAsReadMethod); capabilities.addAll(markEmailAsReadMethod.requiredCapabilities .toCapabilitiesSupportTeamMailboxes(session, accountId)); } // Mark as star/unstar if (isStar != null) { final markEmailAsStarMethod = SetEmailMethod(accountId) ..addUpdates(emails.listEmailIds.generateMapUpdateObjectMarkAsStar( isStar ? MarkStarAction.markStar : MarkStarAction.unMarkStar)); requestBuilder.invocation(markEmailAsStarMethod); capabilities.addAll(markEmailAsStarMethod.requiredCapabilities .toCapabilitiesSupportTeamMailboxes(session, accountId)); } await (requestBuilder..usings(capabilities)).build().execute(); } Future preparingTxtFile(String content) async { final directory = await getTemporaryDirectory(); final file = File('${directory.path}/test.txt'); return file.writeAsString(content); } Future preparingPngWithName(String pngName) async { final bytes = base64Decode(TestImages.base64); final directory = await getTemporaryDirectory(); final file = File('${directory.path}/$pngName.png'); return file.writeAsBytes(bytes); } Future generateImageFromBase64({ required String fileName, required String base64Data, }) async { final bytes = base64Decode(base64Data); final directory = await getTemporaryDirectory(); final file = File('${directory.path}/$fileName'); return file.writeAsBytes(bytes); } Future> uploadAttachments( List attachmentPaths) async { final mailboxDashBoardController = Get.find(); final attachments = []; for (final path in attachmentPaths) { final file = File(path); final fileName = path.split('/').last; final fileInfo = FileInfo( fileName: fileName, filePath: path, fileSize: await file.length(), ); try { final uploadUri = mailboxDashBoardController.sessionCurrent!.getUploadUri( mailboxDashBoardController.accountId.value!, jmapUrl: mailboxDashBoardController.dynamicUrlInterceptors.jmapUrl, ); final uploadAttachmentInteractor = Get.find(); 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) { logWarning('ScenarioUtilsMixin::uploadAttachments(): $e'); return attachments; } } return attachments; } Future getIdentity() async { final mailboxDashBoardController = Get.find(); final getAllIdentitiesInteractor = Get.find(); final getAllIdentities = await getAllIdentitiesInteractor .execute( mailboxDashBoardController.sessionCurrent!, mailboxDashBoardController.accountId.value!, ) .last; return getAllIdentities.fold( (failure) => null, (success) { if (success is GetAllIdentitiesSuccess) { return success.identities?.firstOrNull; } return null; }, ); } bool isMatchingEmailList( List emailList, Set allowedEmails) { if (emailList.length != allowedEmails.length) { return false; } final Set emails = emailList.map((e) => e.email).whereType().toSet(); return emails.length == allowedEmails.length && emails.containsAll(allowedEmails); } Future provisionIdentities( List provisioningIdentities) async { IdentityInteractorsBindings().dependencies(); final mailboxDashBoardController = Get.find(); final createNewIdentityInteractor = Get.find(); final createNewDefaultIdentityInteractor = Get.find(); const uuid = Uuid(); final session = mailboxDashBoardController.sessionCurrent; final accountId = mailboxDashBoardController.accountId.value; final listIdentityRequest = provisioningIdentities .map((provisioningIdentity) => CreateNewIdentityRequest( Id(uuid.v1()), provisioningIdentity.identity, isDefaultIdentity: provisioningIdentity.isDefault, )); for (var identityRequest in listIdentityRequest) { if (identityRequest.isDefaultIdentity) { await createNewDefaultIdentityInteractor .execute(session!, accountId!, identityRequest) .last; } else { await createNewIdentityInteractor .execute(session!, accountId!, identityRequest) .last; } } IdentityInteractorsBindings().dispose(); } void hideKeyboard() { FocusManager.instance.primaryFocus?.unfocus(); } Future mobileBack(PatrolIntegrationTester $) async { if (PlatformInfo.isIOS) { await $.platformAutomator.ios.swipeBack(); } else if (PlatformInfo.isAndroid) { await $.platformAutomator.android.pressBack(); } else { throw UnsupportedError('mobileBack() is only supported on Android/iOS'); } } }