From 919dc9e05f385081a741950ac80f18ff63cd4ff7 Mon Sep 17 00:00:00 2001 From: Julian Adams Date: Sat, 30 Jun 2018 18:41:05 -0500 Subject: [PATCH 1/2] Sent event: open email. Closes #170 --- electron_app/src/DBManager.js | 7 ++-- electron_app/src/clientManager.js | 4 +-- email_composer/src/containers/Composer.js | 19 +++++------ email_composer/src/utils/EmailUtils.js | 12 ++++++- .../__snapshots__/EmailUtils.js.snap | 2 +- email_mailbox/src/actions/index.js | 4 ++- email_mailbox/src/actions/threads.js | 9 +++-- email_mailbox/src/actions/types.js | 3 +- email_mailbox/src/components/PanelWrapper.js | 5 +++ email_mailbox/src/components/ThreadItem.js | 2 +- email_mailbox/src/containers/Panel.js | 8 ++++- email_mailbox/src/reducers/threads.js | 15 +++++++++ email_mailbox/src/utils/EmailUtils.js | 3 +- email_mailbox/src/utils/const.js | 12 ++++--- .../src/utils/electronEventInterface.js | 33 +++++++++++-------- email_mailbox/src/utils/electronInterface.js | 4 +++ 16 files changed, 101 insertions(+), 41 deletions(-) diff --git a/electron_app/src/DBManager.js b/electron_app/src/DBManager.js index 89bf1bd80..283f2cfee 100644 --- a/electron_app/src/DBManager.js +++ b/electron_app/src/DBManager.js @@ -564,16 +564,19 @@ const deleteEmailLabelAndContactByEmailId = (id, optionalEmailToSave) => { }); }; -const updateEmail = ({ id, key, threadId, date, isMuted, unread }) => { +const updateEmail = ({ id, key, threadId, date, isMuted, unread, status }) => { const params = {}; if (key) params.key = key; if (threadId) params.threadId = threadId; if (date) params.date = date; if (typeof unread === 'boolean') params.unread = unread; if (typeof isMuted === 'boolean') params.isMuted = isMuted; + if (status) params.status = status; + + const whereParam = id ? { id } : { key }; return db .table(Table.EMAIL) - .where({ id }) + .where(whereParam) .update(params); }; diff --git a/electron_app/src/clientManager.js b/electron_app/src/clientManager.js index fea9881b1..7d75f66b5 100644 --- a/electron_app/src/clientManager.js +++ b/electron_app/src/clientManager.js @@ -64,8 +64,8 @@ class ClientManager { return client.postKeyBundle(params); } - postOpenEvent(params) { - return client.postOpenEvent(params); + postOpenEvent(metadataKeys) { + return client.postOpenEvent({ metadataKeys }); } postUser(params) { diff --git a/email_composer/src/containers/Composer.js b/email_composer/src/containers/Composer.js index a1ba72846..85b237d78 100644 --- a/email_composer/src/containers/Composer.js +++ b/email_composer/src/containers/Composer.js @@ -11,7 +11,6 @@ import { myAccount, throwError, updateEmail, - updateEmailLabel, saveDraftChanges, errors, deleteEmailsByIds, @@ -26,6 +25,7 @@ import { } from './../utils/ArrayUtils'; import signal from './../libs/signal'; import { + EmailStatus, formOutgoingEmailFromData, formDataToEditDraft, formDataToReply @@ -280,7 +280,7 @@ class ComposerWrapper extends Component { this.setState({ status: Status.WAITING }); const { data, to, subject, body } = formOutgoingEmailFromData( this.state, - LabelType.draft.id + LabelType.sent.id ); let emailId, key; try { @@ -310,15 +310,14 @@ class ComposerWrapper extends Component { const { metadataKey, date } = res.body; const threadId = this.state.threadId || res.body.threadId; key = metadataKey; - const emailParams = { id: emailId, key, threadId, date }; - await updateEmail(emailParams); - - const emailLabelParams = { - emailId, - oldLabelId: LabelType.draft.id, - newLabelId: LabelType.sent.id + const emailParams = { + id: emailId, + key, + threadId, + date, + status: EmailStatus.SENT }; - await updateEmailLabel(emailLabelParams); + await updateEmail(emailParams); closeComposerWindow(emailId); } catch (e) { diff --git a/email_composer/src/utils/EmailUtils.js b/email_composer/src/utils/EmailUtils.js index d5cad42c7..abc9a66f5 100644 --- a/email_composer/src/utils/EmailUtils.js +++ b/email_composer/src/utils/EmailUtils.js @@ -33,6 +33,16 @@ const getCriptextRecipients = (recipients, type) => { })); }; +export const EmailStatus = { + FAIL: 1, + UNSENT: 2, + NONE: 3, + SENDING: 4, + SENT: 5, + DELIVERED: 6, + READ: 7 +}; + export const formOutgoingEmailFromData = (composerData, labelId) => { const recipients = { to: composerData.toEmails, @@ -52,7 +62,7 @@ export const formOutgoingEmailFromData = (composerData, labelId) => { content: body, preview: removeHTMLTags(body).slice(0, 21), date: Date.now(), - status: 1, + status: EmailStatus.SENDING, unread: false, secure: true, isMuted: false diff --git a/email_composer/src/utils/__tests__/__snapshots__/EmailUtils.js.snap b/email_composer/src/utils/__tests__/__snapshots__/EmailUtils.js.snap index 0ab10c352..08be7ea4c 100644 --- a/email_composer/src/utils/__tests__/__snapshots__/EmailUtils.js.snap +++ b/email_composer/src/utils/__tests__/__snapshots__/EmailUtils.js.snap @@ -30,7 +30,7 @@ Object { "preview": " ", "secure": true, - "status": 1, + "status": 4, "subject": "Subject", "unread": false, }, diff --git a/email_mailbox/src/actions/index.js b/email_mailbox/src/actions/index.js index 9cdfcc751..caa67f1ed 100644 --- a/email_mailbox/src/actions/index.js +++ b/email_mailbox/src/actions/index.js @@ -20,7 +20,8 @@ import { selectThreads, removeThreads, removeThreadsLabel, - sendOpenEvent + sendOpenEvent, + updateStatusThread } from './threads'; import { addEmails, @@ -90,6 +91,7 @@ export { updateFeedItemSuccess, updateLabel, updateLabelSuccess, + updateStatusThread, updateUnreadEmails, updateUnreadThread, updateUnreadThreads diff --git a/email_mailbox/src/actions/threads.js b/email_mailbox/src/actions/threads.js index c4d91c1bc..31a13cfa7 100644 --- a/email_mailbox/src/actions/threads.js +++ b/email_mailbox/src/actions/threads.js @@ -106,6 +106,12 @@ export const moveThreads = (threadIds, labelId) => ({ labelId }); +export const updateStatusThread = (threadId, newStatus) => ({ + type: Thread.UPDATE_STATUS, + status: newStatus, + threadId +}); + export const updateUnreadThread = thread => { return { type: Thread.UPDATE_UNREAD_THREAD, @@ -308,8 +314,7 @@ export const sendOpenEvent = threadId => { const unreadEmails = await getUnreadEmailsByThreadId(threadId); if (unreadEmails.length > 0) { const metadataKeys = unreadEmails.map(item => Number(item.key)); - const params = { metadataKeys }; - await postOpenEvent(params); + await postOpenEvent(metadataKeys); } } catch (e) { // TO DO diff --git a/email_mailbox/src/actions/types.js b/email_mailbox/src/actions/types.js index aa8b975c4..b20b67e9f 100644 --- a/email_mailbox/src/actions/types.js +++ b/email_mailbox/src/actions/types.js @@ -18,7 +18,8 @@ export const Thread = { MOVE_THREADS: 'MOVE_THREADS', UPDATE_UNREAD_THREADS: 'UPDATE_UNREAD_THREADS', UPDATE_UNREAD_THREAD: 'UPDATE_UNREAD_THREAD', - ADD_EMAIL: 'UPDATE_THREAD_EMAIL_IDS' + ADD_EMAIL: 'UPDATE_THREAD_EMAIL_IDS', + UPDATE_STATUS: 'UPDATE_STATUS' }; export const Contact = { diff --git a/email_mailbox/src/components/PanelWrapper.js b/email_mailbox/src/components/PanelWrapper.js index 57f9f0169..4c101f952 100644 --- a/email_mailbox/src/components/PanelWrapper.js +++ b/email_mailbox/src/components/PanelWrapper.js @@ -68,6 +68,10 @@ class PanelWrapper extends Component { } }); + addEvent(Event.EMAIL_TRACKING_UPDATE, threadId => { + props.onMarkThreadAsOpen(threadId); + }); + addEvent(Event.UPDATE_THREAD_EMAILS, eventParams => { const newThreadId = eventParams.threadId; props.onLoadEmails(newThreadId); @@ -178,6 +182,7 @@ class PanelWrapper extends Component { PanelWrapper.propTypes = { onAddEmailToThread: PropTypes.func, onLoadEmails: PropTypes.func, + onMarkThreadAsOpen: PropTypes.func, onLoadThreads: PropTypes.func, onUpdateOpenedAccount: PropTypes.func, onUpdateTimestamp: PropTypes.func, diff --git a/email_mailbox/src/components/ThreadItem.js b/email_mailbox/src/components/ThreadItem.js index f32fa6a3f..2497a82e8 100644 --- a/email_mailbox/src/components/ThreadItem.js +++ b/email_mailbox/src/components/ThreadItem.js @@ -88,7 +88,7 @@ class ThreadItem extends Component { return ; case EmailStatus.DELIVERED: return ; - case EmailStatus.OPENED: + case EmailStatus.READ: return ; default: return null; diff --git a/email_mailbox/src/containers/Panel.js b/email_mailbox/src/containers/Panel.js index de39be041..c238ca787 100644 --- a/email_mailbox/src/containers/Panel.js +++ b/email_mailbox/src/containers/Panel.js @@ -4,7 +4,8 @@ import { loadThreads, updateLabelSuccess, updateAllFeedItemsAsOlder, - loadEmails + loadEmails, + updateStatusThread } from '../actions'; import PanelWrapper from '../components/PanelWrapper'; import { @@ -13,6 +14,7 @@ import { updateAccount } from '../utils/electronInterface'; import { storeSeenTimestamp } from '../utils/storage'; +import { EmailStatus } from '../utils/const'; const mapStateToProps = state => { const threadsCount = state.get('threads').size; @@ -46,6 +48,10 @@ const mapDispatchToProps = dispatch => { const rejectedLabelIds = defineRejectedLabels(labelId); dispatch(loadThreads({ ...params, ...rejectedLabelIds })); }, + onMarkThreadAsOpen: threadId => { + const readStatus = EmailStatus.READ; + dispatch(updateStatusThread(threadId, readStatus)); + }, onUpdateOpenedAccount: async () => { const opened = true; const recipientId = myAccount.recipientId; diff --git a/email_mailbox/src/reducers/threads.js b/email_mailbox/src/reducers/threads.js index d11813a8e..a1e2b40cf 100644 --- a/email_mailbox/src/reducers/threads.js +++ b/email_mailbox/src/reducers/threads.js @@ -137,6 +137,18 @@ const threads = (state = List([]), action) => { return thread; }); } + case Thread.UPDATE_STATUS: { + const { status, threadId } = action; + if (!threadId || !status) { + return state; + } + return state.map(threadItem => { + if (threadItem.get('id') === threadId) { + return thread(threadItem, action); + } + return thread; + }); + } default: return state; } @@ -150,6 +162,9 @@ const thread = (state, action) => { case Thread.ADD_EMAIL: { return state.set('emailIds', state.get('emailIds').push(action.emailId)); } + case Thread.UPDATE_STATUS: { + return state.update('status', action.status); + } default: return state; } diff --git a/email_mailbox/src/utils/EmailUtils.js b/email_mailbox/src/utils/EmailUtils.js index eb8766c3f..7c008e3c9 100644 --- a/email_mailbox/src/utils/EmailUtils.js +++ b/email_mailbox/src/utils/EmailUtils.js @@ -1,5 +1,6 @@ import { removeAppDomain, removeHTMLTags } from './StringUtils'; import signal from './../libs/signal'; +import { EmailStatus } from './const'; const getContentMessage = async ({ bodyKey, @@ -49,7 +50,7 @@ export const formIncomingEmailFromData = async data => { preview, subject: data.subject, date: data.date, - status: 1, + status: EmailStatus.NONE, unread: true, secure: true, isMuted: false diff --git a/email_mailbox/src/utils/const.js b/email_mailbox/src/utils/const.js index 3a1722363..61007ca88 100644 --- a/email_mailbox/src/utils/const.js +++ b/email_mailbox/src/utils/const.js @@ -48,11 +48,13 @@ export const FeedItemType = { }; export const EmailStatus = { - UNSENT: -1, - NONE: 0, - SENT: 1, - DELIVERED: 2, - OPENED: 3 + FAIL: 1, + UNSENT: 2, + NONE: 3, + SENDING: 4, + SENT: 5, + DELIVERED: 6, + READ: 7 }; export const SocketCommand = { diff --git a/email_mailbox/src/utils/electronEventInterface.js b/email_mailbox/src/utils/electronEventInterface.js index f0f922074..cb1a1098c 100644 --- a/email_mailbox/src/utils/electronEventInterface.js +++ b/email_mailbox/src/utils/electronEventInterface.js @@ -7,7 +7,8 @@ import { LabelType, getContactByEmails, createFeedItem, - myAccount + myAccount, + updateOpenedEmailByKey } from './electronInterface'; import { formEmailLabel, @@ -15,7 +16,7 @@ import { formIncomingEmailFromData, getRecipientsFromData } from './EmailUtils'; -import { SocketCommand, appDomain, FeedItemType } from './const'; +import { SocketCommand, appDomain, FeedItemType, EmailStatus } from './const'; const EventEmitter = window.require('events'); const electron = window.require('electron'); @@ -92,18 +93,24 @@ export const handleNewMessageEvent = async ({ rowid, params }) => { export const handleEmailTrackingUpdate = async ({ rowid, params }) => { const [metadataKey, recipientId] = [params.metadataKey, params.from]; if (recipientId !== myAccount.recipientId) { - const contactEmail = `${recipientId}@${appDomain}`; - const [contact] = await getContactByEmails([contactEmail]); const [email] = await getEmailByKey(metadataKey); - const feedItemParams = { - date: params.date, - type: FeedItemType.OPENED.value, - emailId: email.id, - contactId: contact.id - }; - await createFeedItem([feedItemParams]); - await acknowledgeEvents([rowid]); - emitter.emit(Event.EMAIL_TRACKING_UPDATE); + if (email) { + await updateOpenedEmailByKey({ + key: metadataKey, + status: EmailStatus.READ + }); + const contactEmail = `${recipientId}@${appDomain}`; + const [contact] = await getContactByEmails([contactEmail]); + const feedItemParams = { + date: params.date, + type: FeedItemType.OPENED.value, + emailId: email.id, + contactId: contact.id + }; + await createFeedItem([feedItemParams]); + await acknowledgeEvents([rowid]); + emitter.emit(Event.EMAIL_TRACKING_UPDATE, email.id); + } } // To do: Sync this event with my other devices }; diff --git a/email_mailbox/src/utils/electronInterface.js b/email_mailbox/src/utils/electronInterface.js index 1bf45640d..5753967f1 100644 --- a/email_mailbox/src/utils/electronInterface.js +++ b/email_mailbox/src/utils/electronInterface.js @@ -237,6 +237,10 @@ export const updateLabel = params => { return dbManager.updateLabel(params); }; +export const updateOpenedEmailByKey = ({ key, status }) => { + return dbManager.updateLabel({ key, status }); +}; + export const updateUnreadEmailByThreadId = (threadId, value) => { return dbManager.updateEmailByThreadId({ threadId, unread: value }); }; From 99dd5c8eba15373dabb33a10c891186a6bd5c291 Mon Sep 17 00:00:00 2001 From: Julian Adams Date: Mon, 2 Jul 2018 17:37:59 -0500 Subject: [PATCH 2/2] Requested changes --- electron_app/package.json | 2 +- electron_app/src/DBManager.js | 17 +++++++------- electron_app/src/clientManager.js | 2 +- electron_app/yarn.lock | 2 +- email_mailbox/src/actions/threads.js | 6 ++--- email_mailbox/src/components/PanelWrapper.js | 4 ++-- .../src/reducers/__tests__/threads.js | 22 +++++++++++++++++++ email_mailbox/src/reducers/threads.js | 6 ++--- .../src/utils/electronEventInterface.js | 4 ++-- email_mailbox/src/utils/electronInterface.js | 2 +- 10 files changed, 45 insertions(+), 22 deletions(-) diff --git a/electron_app/package.json b/electron_app/package.json index 15e2f7dc3..78b3cb35a 100644 --- a/electron_app/package.json +++ b/electron_app/package.json @@ -75,7 +75,7 @@ "electron-packager": "^10.1.2" }, "dependencies": { - "@criptext/email-http-client": "^0.8.1", + "@criptext/email-http-client": "^0.8.2", "knex": "^0.14.2", "sqlite3": "^3.1.13", "websocket": "^1.0.25" diff --git a/electron_app/src/DBManager.js b/electron_app/src/DBManager.js index 283f2cfee..598fddecf 100644 --- a/electron_app/src/DBManager.js +++ b/electron_app/src/DBManager.js @@ -1,5 +1,6 @@ const { db, cleanDataBase, createTables, Table } = require('./models.js'); const { formContactsRow } = require('./utils/dataTableUtils.js'); +const { noNulls } = require('./utils/ObjectUtils'); /* Account ----------------------------- */ @@ -565,14 +566,14 @@ const deleteEmailLabelAndContactByEmailId = (id, optionalEmailToSave) => { }; const updateEmail = ({ id, key, threadId, date, isMuted, unread, status }) => { - const params = {}; - if (key) params.key = key; - if (threadId) params.threadId = threadId; - if (date) params.date = date; - if (typeof unread === 'boolean') params.unread = unread; - if (typeof isMuted === 'boolean') params.isMuted = isMuted; - if (status) params.status = status; - + const params = noNulls({ + key, + threadId, + date, + unread: typeof unread === 'boolean' ? unread : undefined, + isMuted: typeof isMuted === 'boolean' ? isMuted : undefined, + status + }); const whereParam = id ? { id } : { key }; return db .table(Table.EMAIL) diff --git a/electron_app/src/clientManager.js b/electron_app/src/clientManager.js index 7d75f66b5..8001e3ac3 100644 --- a/electron_app/src/clientManager.js +++ b/electron_app/src/clientManager.js @@ -65,7 +65,7 @@ class ClientManager { } postOpenEvent(metadataKeys) { - return client.postOpenEvent({ metadataKeys }); + return client.postOpenEvent(metadataKeys); } postUser(params) { diff --git a/electron_app/yarn.lock b/electron_app/yarn.lock index ef5e957b9..015520446 100644 --- a/electron_app/yarn.lock +++ b/electron_app/yarn.lock @@ -96,7 +96,7 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@criptext/email-http-client@^0.8.1": +"@criptext/email-http-client@^0.8.2": version "0.8.2" resolved "https://registry.yarnpkg.com/@criptext/email-http-client/-/email-http-client-0.8.2.tgz#6e788b0ea3e2e959b7b6bd46829ede7caaa20ec4" dependencies: diff --git a/email_mailbox/src/actions/threads.js b/email_mailbox/src/actions/threads.js index 31a13cfa7..7392bec8a 100644 --- a/email_mailbox/src/actions/threads.js +++ b/email_mailbox/src/actions/threads.js @@ -106,10 +106,10 @@ export const moveThreads = (threadIds, labelId) => ({ labelId }); -export const updateStatusThread = (threadId, newStatus) => ({ +export const updateStatusThread = (threadId, status) => ({ type: Thread.UPDATE_STATUS, - status: newStatus, - threadId + threadId, + status }); export const updateUnreadThread = thread => { diff --git a/email_mailbox/src/components/PanelWrapper.js b/email_mailbox/src/components/PanelWrapper.js index 4c101f952..6c06e76c3 100644 --- a/email_mailbox/src/components/PanelWrapper.js +++ b/email_mailbox/src/components/PanelWrapper.js @@ -73,8 +73,8 @@ class PanelWrapper extends Component { }); addEvent(Event.UPDATE_THREAD_EMAILS, eventParams => { - const newThreadId = eventParams.threadId; - props.onLoadEmails(newThreadId); + const { threadId } = eventParams; + props.onLoadEmails(threadId); props.onAddEmailToThread({ threadId: this.state.sectionSelected.params.threadIdSelected, emailId: eventParams.emailId diff --git a/email_mailbox/src/reducers/__tests__/threads.js b/email_mailbox/src/reducers/__tests__/threads.js index 568a978c6..a96b20183 100644 --- a/email_mailbox/src/reducers/__tests__/threads.js +++ b/email_mailbox/src/reducers/__tests__/threads.js @@ -33,4 +33,26 @@ describe('Set thread state by actions', () => { const unread = emailUpdated.get('unread'); expect(unread).toBe(false); }); + + it('should set thread param: status, action[UPDATE_STATUS]', () => { + const state = initState(threads); + const threadId = 1; + const newStatus = 2; + const action = actions.updateStatusThread(threadId, newStatus); + const newState = threadsReducer(state, action); + const emailUpdated = newState.get('0'); + const status = emailUpdated.get('status'); + expect(status).toBe(newStatus); + }); + + it('should not set thread param status because is undefined, action[UPDATE_STATUS]', () => { + const state = initState(threads); + const threadId = 1; + const badStatus = undefined; + const action = actions.updateStatusThread(threadId, badStatus); + const newState = threadsReducer(state, action); + const emailUpdated = newState.get('0'); + const status = emailUpdated.get('status'); + expect(status).not.toBe(badStatus); + }); }); diff --git a/email_mailbox/src/reducers/threads.js b/email_mailbox/src/reducers/threads.js index a1e2b40cf..a6fb123f8 100644 --- a/email_mailbox/src/reducers/threads.js +++ b/email_mailbox/src/reducers/threads.js @@ -134,7 +134,7 @@ const threads = (state = List([]), action) => { if (threadItem.get('id') === threadId) { return thread(threadItem, action); } - return thread; + return threadItem; }); } case Thread.UPDATE_STATUS: { @@ -146,7 +146,7 @@ const threads = (state = List([]), action) => { if (threadItem.get('id') === threadId) { return thread(threadItem, action); } - return thread; + return threadItem; }); } default: @@ -163,7 +163,7 @@ const thread = (state, action) => { return state.set('emailIds', state.get('emailIds').push(action.emailId)); } case Thread.UPDATE_STATUS: { - return state.update('status', action.status); + return state.set('status', action.status); } default: return state; diff --git a/email_mailbox/src/utils/electronEventInterface.js b/email_mailbox/src/utils/electronEventInterface.js index cb1a1098c..96bb27a95 100644 --- a/email_mailbox/src/utils/electronEventInterface.js +++ b/email_mailbox/src/utils/electronEventInterface.js @@ -16,7 +16,7 @@ import { formIncomingEmailFromData, getRecipientsFromData } from './EmailUtils'; -import { SocketCommand, appDomain, FeedItemType, EmailStatus } from './const'; +import { SocketCommand, appDomain, EmailStatus } from './const'; const EventEmitter = window.require('events'); const electron = window.require('electron'); @@ -103,7 +103,7 @@ export const handleEmailTrackingUpdate = async ({ rowid, params }) => { const [contact] = await getContactByEmails([contactEmail]); const feedItemParams = { date: params.date, - type: FeedItemType.OPENED.value, + type: params.type, emailId: email.id, contactId: contact.id }; diff --git a/email_mailbox/src/utils/electronInterface.js b/email_mailbox/src/utils/electronInterface.js index 5753967f1..ce286ad41 100644 --- a/email_mailbox/src/utils/electronInterface.js +++ b/email_mailbox/src/utils/electronInterface.js @@ -238,7 +238,7 @@ export const updateLabel = params => { }; export const updateOpenedEmailByKey = ({ key, status }) => { - return dbManager.updateLabel({ key, status }); + return dbManager.updateEmail({ key, status }); }; export const updateUnreadEmailByThreadId = (threadId, value) => {