From 1e1a008934dd12f67ce1f85e4895e6de34d6a956 Mon Sep 17 00:00:00 2001 From: Alexey Lunin <alexey.lunin@vereign.com> Date: Thu, 5 Oct 2023 14:11:35 +0300 Subject: [PATCH] Implement autosave --- .env | 2 +- .env.sample | 2 +- src/screens/EmailDetails/SaveSection.tsx | 61 ++++++----------- src/screens/EmailDetails/index.tsx | 61 ++--------------- src/store/AgentStore.ts | 86 +++++++++++++++++++++++- 5 files changed, 113 insertions(+), 99 deletions(-) diff --git a/.env b/.env index 418a5bb..7fd01c4 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ MEDIATOR_URL=https://ssi-dev.vereign.com/hin/afj-mediator/invite?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiJmOGFkYzVjZC01ZmU1LTQ5MjktODJjOC00MDdhZDY0N2I0MzQiLCJsYWJlbCI6IlZlcmVpZ24tTWVkaWF0b3IiLCJhY2NlcHQiOlsiZGlkY29tbS9haXAxIiwiZGlkY29tbS9haXAyO2Vudj1yZmMxOSJdLCJoYW5kc2hha2VfcHJvdG9jb2xzIjpbImh0dHBzOi8vZGlkY29tbS5vcmcvZGlkZXhjaGFuZ2UvMS4wIiwiaHR0cHM6Ly9kaWRjb21tLm9yZy9jb25uZWN0aW9ucy8xLjAiXSwic2VydmljZXMiOlt7ImlkIjoiI2lubGluZS0wIiwic2VydmljZUVuZHBvaW50IjoiaHR0cHM6Ly9zc2ktZGV2LnZlcmVpZ24uY29tL2hpbi9hZmotbWVkaWF0b3IiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa2o5TVI5dVdyZjhvWU00WXNla2VpZjNvbTJTaHY2VUpuc3hWQXdkNkdKbk1tIl0sInJvdXRpbmdLZXlzIjpbXX0seyJpZCI6IiNpbmxpbmUtMSIsInNlcnZpY2VFbmRwb2ludCI6IndzOi8vc3NpLWRldi52ZXJlaWduLmNvbS9oaW4vYWZqLW1lZGlhdG9yIiwidHlwZSI6ImRpZC1jb21tdW5pY2F0aW9uIiwicmVjaXBpZW50S2V5cyI6WyJkaWQ6a2V5Ono2TWtqOU1SOXVXcmY4b1lNNFlzZWtlaWYzb20yU2h2NlVKbnN4VkF3ZDZHSm5NbSJdLCJyb3V0aW5nS2V5cyI6W119XX0 -SVDX_BASE_URL=https://did.svdx.pr \ No newline at end of file +SVDX_BASE_URL=https://did.svdx.pro \ No newline at end of file diff --git a/.env.sample b/.env.sample index d520aac..df29dfc 100644 --- a/.env.sample +++ b/.env.sample @@ -1,5 +1,5 @@ MEDIATOR_URL=https://gaiax.vereign.com/mediator?c_i=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9jb25uZWN0aW9ucy8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiZDU0Mjc2ZDUtMDUwYy00MDI1LWExYWUtNGYzMzE4MWQyM2U3IiwgImxhYmVsIjogIk1lZGlhdG9yIiwgInJlY2lwaWVudEtleXMiOiBbIkJjdGoyQllHUWN5dVRTaVlEV0tjTWNjRDNvR3Q3ZkNDellaV0trbkVNdFA5Il0sICJzZXJ2aWNlRW5kcG9pbnQiOiAiaHR0cHM6Ly9nYWlheC52ZXJlaWduLmNvbS9tZWRpYXRvciJ9 -SVDX_BASE_URL=https://did.svdx.pr +SVDX_BASE_URL=https://did.svdx.pro # MEDIATOR_URL=https://mediator.dev.animo.id/invite?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiIyMDc1MDM4YS05ZGU3LTRiODItYWUxYi1jNzBmNDg4MjYzYTciLCJsYWJlbCI6IkFuaW1vIE1lZGlhdG9yIiwiYWNjZXB0IjpbImRpZGNvbW0vYWlwMSIsImRpZGNvbW0vYWlwMjtlbnY9cmZjMTkiXSwiaGFuZHNoYWtlX3Byb3RvY29scyI6WyJodHRwczovL2RpZGNvbW0ub3JnL2RpZGV4Y2hhbmdlLzEuMCIsImh0dHBzOi8vZGlkY29tbS5vcmcvY29ubmVjdGlvbnMvMS4wIl0sInNlcnZpY2VzIjpbeyJpZCI6IiNpbmxpbmUtMCIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHBzOi8vbWVkaWF0b3IuZGV2LmFuaW1vLmlkIiwidHlwZSI6ImRpZC1jb21tdW5pY2F0aW9uIiwicmVjaXBpZW50S2V5cyI6WyJkaWQ6a2V5Ono2TWtvSG9RTUphdU5VUE5OV1pQcEw3RGs1SzNtQ0NDMlBpNDJGY3FwR25iampMcSJdLCJyb3V0aW5nS2V5cyI6W119LHsiaWQiOiIjaW5saW5lLTEiLCJzZXJ2aWNlRW5kcG9pbnQiOiJ3c3M6Ly9tZWRpYXRvci5kZXYuYW5pbW8uaWQiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa29Ib1FNSmF1TlVQTk5XWlBwTDdEazVLM21DQ0MyUGk0MkZjcXBHbmJqakxxIl0sInJvdXRpbmdLZXlzIjpbXX1dfQ # MEDIATOR_URL=https://ssi-dev.vereign.com/hin/afj-mediator/invite?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiI1OTRkMTk3YS0yMzgxLTRkNmUtOTk1ZC0xODBjMzNiY2M1MGYiLCJsYWJlbCI6ImFmai12ZXJlaWduLW1lZGlhdG9yIiwiYWNjZXB0IjpbImRpZGNvbW0vYWlwMSIsImRpZGNvbW0vYWlwMjtlbnY9cmZjMTkiXSwiaGFuZHNoYWtlX3Byb3RvY29scyI6WyJodHRwczovL2RpZGNvbW0ub3JnL2RpZGV4Y2hhbmdlLzEuMCIsImh0dHBzOi8vZGlkY29tbS5vcmcvY29ubmVjdGlvbnMvMS4wIl0sInNlcnZpY2VzIjpbeyJpZCI6IiNpbmxpbmUtMCIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHBzOi8vc3NpLWRldi52ZXJlaWduLmNvbS9oaW4vYWZqLW1lZGlhdG9yIiwidHlwZSI6ImRpZC1jb21tdW5pY2F0aW9uIiwicmVjaXBpZW50S2V5cyI6WyJkaWQ6a2V5Ono2TWtvM0g0YWNvZ05mSHFaeUtHVERpdWRCd3o4TTU0dXRoR1ZBWFhnQzE3eHZFTCJdLCJyb3V0aW5nS2V5cyI6W119LHsiaWQiOiIjaW5saW5lLTEiLCJzZXJ2aWNlRW5kcG9pbnQiOiJ3czovL3NzaS1kZXYudmVyZWlnbi5jb20vaGluL2Fmai1tZWRpYXRvciIsInR5cGUiOiJkaWQtY29tbXVuaWNhdGlvbiIsInJlY2lwaWVudEtleXMiOlsiZGlkOmtleTp6Nk1rbzNINGFjb2dOZkhxWnlLR1REaXVkQnd6OE01NHV0aEdWQVhYZ0MxN3h2RUwiXSwicm91dGluZ0tleXMiOltdfV19 diff --git a/src/screens/EmailDetails/SaveSection.tsx b/src/screens/EmailDetails/SaveSection.tsx index e67a5be..f5fcba9 100644 --- a/src/screens/EmailDetails/SaveSection.tsx +++ b/src/screens/EmailDetails/SaveSection.tsx @@ -1,53 +1,32 @@ import React from 'react'; -import { format } from 'date-fns'; import {StyleSheet, Text, View} from 'react-native'; -import { ColorPallet, TextTheme } from 'src/theme/theme'; +import {ColorPallet, TextTheme} from 'src/theme/theme'; import Card from 'src/components/EmailCard'; -import { DATE_TIME_FORMAT } from "src/constants/constants"; -import {parseAddress} from "src/utils/email"; import Button, {ButtonType} from "../../components/Button"; interface Props { configInvalid: boolean; - saving: boolean; - saved: boolean; - userEmail: string | undefined; - onSavePress: () => void; + onSettingsPress: () => void; } -const SaveSection = ({ configInvalid, saving, saved, userEmail, onSavePress }: Props) => { +const SaveSection = ({ configInvalid, onSettingsPress }: Props) => { + if (!configInvalid) return null; return ( <Card background="white"> - <View style={styles.saveWrapper}> + <Text style={styles.warn}> + IMAP Configuration Missing! + </Text> + <Text style={styles.text}> + In order to save your messages securely, you need to set up your IMAP configuration correctly. Currently, the provided IMAP settings are not valid. Please review and update the IMAP configuration in the settings to ensure your messages are saved and accessible. + </Text> + <View> <Button - title="Save using IMAP" - disabled={configInvalid || saving || saved} buttonType={ButtonType.Primary} - onPress={onSavePress} + title="Configure IMAP Settings" + buttonStyle={styles.goToImapButton} + onPress={onSettingsPress} /> </View> - - {!saving && !saved && !configInvalid && ( - <Text style={styles.text}> - Press the button to save to {userEmail} - </Text> - )} - - {saving && ( - <Text style={styles.text}> - Saving to {userEmail} - </Text> - )} - {saved && ( - <Text style={styles.text}> - Message saved to {userEmail} - </Text> - )} - {configInvalid && ( - <Text style={styles.warn}> - The IMAP config is not valid. Please check the IMAP configuration in the settings. - </Text> - )} </Card> ); }; @@ -55,17 +34,15 @@ const SaveSection = ({ configInvalid, saving, saved, userEmail, onSavePress }: P export default SaveSection; const styles = StyleSheet.create({ - saveWrapper: { - }, warn: { ...TextTheme.normal, color: ColorPallet.baseColors.red, - paddingTop: 12, + marginBottom: 6 }, text: { - color: ColorPallet.baseColors.black, - fontWeight: 'bold', - fontSize: 16, - paddingTop: 12, + ...TextTheme.normal, }, + goToImapButton: { + marginTop: 16 + } }); diff --git a/src/screens/EmailDetails/index.tsx b/src/screens/EmailDetails/index.tsx index 66031b2..e38ac0c 100644 --- a/src/screens/EmailDetails/index.tsx +++ b/src/screens/EmailDetails/index.tsx @@ -2,21 +2,16 @@ import React, { useEffect, useState } from 'react'; import { StackScreenProps } from '@react-navigation/stack'; import { StyleSheet, - Text, View, StatusBar, ScrollView, NativeModules, } from 'react-native'; import {observer} from "mobx-react"; -import {EmailStackParams, Screens} from 'src/type/navigators'; -import { ColorPallet, TextTheme } from 'src/theme/theme'; +import {EmailStackParams, Screens, Stacks} from 'src/type/navigators'; import MimeParser from "@vereign/lib-mime"; import {getImapConfig} from "src/utils/keychain"; -import {successToast, warningToast} from "src/utils/toast"; -import Button, {ButtonType} from "src/components/Button"; -import Config from "react-native-config"; -import axios from "axios"; +import {warningToast} from "src/utils/toast"; import { useObject, useRealm } from '@realm/react'; import {useNavigation} from "@react-navigation/native"; import Email from 'src/db-models/Email'; @@ -25,8 +20,6 @@ import Subject from './Subject'; import ContentCard from './ContentCard'; import SaveSection from "./SaveSection"; -const {VereignImapModule} = NativeModules; - type EmailDetailsProps = StackScreenProps< EmailStackParams, Screens.EmailDetails @@ -48,8 +41,6 @@ const EmailDetails: React.FC<EmailDetailsProps> = observer(({ } const [configValid, setConfigValid] = useState(true); - const [savingToEmailBox, setSavingToEmailBox] = useState(false); - const [userEmail, setUserEmail] = useState(''); const [html, setHtml] = useState(''); const [plainText, setPlainText] = useState(''); @@ -59,7 +50,6 @@ const EmailDetails: React.FC<EmailDetailsProps> = observer(({ setConfigValid(false); return; } - setUserEmail(config.username); } const parseMime = async () => { try { @@ -86,44 +76,6 @@ const EmailDetails: React.FC<EmailDetailsProps> = observer(({ parseMime(); }, [realmId]); - const saveEmail = async () => { - setSavingToEmailBox(true); - try { - const config = await getImapConfig(); - if (config) { - VereignImapModule.saveMessage(config!.host, config!.username, config!.password, email.svdxMime, (success: boolean, error: any) => { - if (success) { - successToast("Email is saved"); - realm.write(() => { - email.svdxImapSaved = true; - }); - notifySVDXServer(); - } - if (error) { - warningToast("Something went wrong " + error); - } - setSavingToEmailBox(false); - }); - } - } catch (e: any) { - warningToast(e.message); - setSavingToEmailBox(false); - } - } - - const notifySVDXServer = async () => { - const response = await axios({ - url: `${Config.SVDX_BASE_URL}/v1/message/read`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - data: { - messageId: email.svdxMessageId - }, - }); - } - return ( <View style={styles.container}> <StatusBar barStyle="light-content" /> @@ -132,10 +84,11 @@ const EmailDetails: React.FC<EmailDetailsProps> = observer(({ <View style={styles.content}> <SaveSection configInvalid={!configValid} - saving={savingToEmailBox} - saved={email.svdxImapSaved || false} - userEmail={userEmail} - onSavePress={() => saveEmail()} + onSettingsPress={() => { + navigation.getParent().navigate(Stacks.SettingsStack, { + screen: Screens.ImapConfiguration + }); + }} /> <SentBy diff --git a/src/store/AgentStore.ts b/src/store/AgentStore.ts index 88e15ff..ab88e7b 100644 --- a/src/store/AgentStore.ts +++ b/src/store/AgentStore.ts @@ -65,12 +65,16 @@ import {WalletConfig, WalletExportImportConfig} from "@aries-framework/core/buil import { LegacyIndyCredentialFormatService } from "@aries-framework/anoncreds/build/formats/LegacyIndyCredentialFormatService"; -import {infoToast, warningToast} from 'src/utils/toast'; +import {infoToast, successToast, warningToast} from 'src/utils/toast'; import {Buffer} from "buffer"; import Realm from "realm"; import MimeParser from "@vereign/lib-mime"; import notifee, {AndroidImportance, AuthorizationStatus} from '@notifee/react-native'; import Email from "../db-models/Email"; +import axios from "axios"; +import {NativeModules} from "react-native"; + +const {VereignImapModule} = NativeModules; class AgentStore { private _rootStore: RootStore; @@ -302,6 +306,8 @@ class AgentStore { infoToast("Received new message"); + await this._saveEmail(svdxId, realmRecordId, emailContent); + this._displayNewEmailReceived(from, subject, realmRecordId.toString()); } catch (e) { warningToast("Email is received but it can not be decoded"); @@ -310,6 +316,84 @@ class AgentStore { } } + private _saveEmail = async (svdxMessageId: string, realmId: Realm.BSON.ObjectId, mime: string) => { + try { + const config = await getImapConfig(); + if (config) { + if (!(await this._checkCanSaveEmail(svdxMessageId))) return; + + VereignImapModule.saveMessage(config!.host, config!.username, config!.password, mime, (success: boolean, error: any) => { + if (success) { + successToast("Email is saved"); + const email = this._realm.objectForPrimaryKey('Email', realmId); + + if (email) { + this._realm.write(() => { + email.svdxImapSaved = true; + }); + this._notifySVDXServer(svdxMessageId); + } + } + if (error) { + warningToast("Something went wrong " + error); + } + }); + } + } catch (e: any) { + warningToast(e.message); + } + } + + private _checkCanSaveEmail = async (svdxMessageId: string) => { + return true; // TODO Once https://code.vereign.com/ssi/didcomm-mail/svdx/-/merge_requests/33 merged and deployed, remove this line + try { + const response = await axios({ + url: `${Config.SVDX_BASE_URL}/v1/message/status`, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: { + messageId: svdxMessageId + }, + }); + + // Check for HTTP 200 status + if (response.status === 200) { + return true; + } + return false + } catch (error: any) { + if (error.response && error.response.status === 404) { + // Handle the case where the message has been delivered already in another way + console.log('Message has been delivered already in another way'); + } else { + // Handle other errors + console.error('An error occurred:', error.message); + } + } + return false; + } + + private _notifySVDXServer = async (svdxMessageId: string) => { + try { + await axios({ + url: `${Config.SVDX_BASE_URL}/v1/message/read`, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: { + messageId: svdxMessageId + }, + }); + console.log('Message has been marked as read'); + } catch (e: any) { + console.error('Something wen wrong during notifying SVDX server about read message', e.message); + } + + } + private _displayNewEmailReceived = async (from: string, subject: string, realmId: string) => { const authResult = await notifee.requestPermission() if (authResult.authorizationStatus !== AuthorizationStatus.AUTHORIZED) { -- GitLab