From 179f24449ba29edb5295391255175a9b55eaf400 Mon Sep 17 00:00:00 2001 From: Jackie Luo Date: Mon, 27 Jun 2016 14:52:05 -0700 Subject: [PATCH] Refactor code and add test for threading --- packages/nylas-message-processor/index.js | 11 ++- .../processors/threading.js | 22 +++-- .../spec/fixtures/thread.js | 94 +++++++++++++++++++ .../spec/threading-spec.js | 58 ++++++++++++ packages/nylas-sync/sync-process-manager.js | 2 +- 5 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 packages/nylas-message-processor/spec/fixtures/thread.js create mode 100644 packages/nylas-message-processor/spec/threading-spec.js diff --git a/packages/nylas-message-processor/index.js b/packages/nylas-message-processor/index.js index 3d2844ebd..853d8fd73 100644 --- a/packages/nylas-message-processor/index.js +++ b/packages/nylas-message-processor/index.js @@ -9,9 +9,9 @@ global.Promise = require('bluebird'); const MessageAttributes = ['body', 'processed'] const MessageProcessorVersion = 1; -function runPipeline(accountId, message) { +function runPipeline({db, accountId, message}) { return processors.reduce((prevPromise, processor) => ( - prevPromise.then((msg) => processor({message: msg, accountId})) + prevPromise.then((msg) => processor({db, accountId, message: msg})) ), Promise.resolve(message)) } @@ -24,9 +24,10 @@ function saveMessage(message) { function processMessage({messageId, accountId}) { DatabaseConnector.forAccount(accountId) - .then(({Message}) => + .then((db) => { + const {Message} = db Message.find({where: {id: messageId}}).then((message) => - runPipeline(accountId, message) + runPipeline({db, accountId, message}) .then((processedMessage) => saveMessage(processedMessage)) .catch((err) => console.error(`MessageProcessor Failed: ${err}`) @@ -35,7 +36,7 @@ function processMessage({messageId, accountId}) { .catch((err) => console.error(`MessageProcessor: Couldn't find message id ${messageId} in accountId: ${accountId}: ${err}`) ) - ) + }) } module.exports = { diff --git a/packages/nylas-message-processor/processors/threading.js b/packages/nylas-message-processor/processors/threading.js index 8f5922b0f..7af8bbee9 100644 --- a/packages/nylas-message-processor/processors/threading.js +++ b/packages/nylas-message-processor/processors/threading.js @@ -50,13 +50,15 @@ function findCorrespondingThread({message, threads}) { function removeBccParticipants({message, match}) { const matchBcc = match.bcc ? match.bcc : [] const messageBcc = message.bcc ? message.bcc : [] - let matchEmails = match.participants.filter((participant) => { + const matchParticipants = [...match.from, ...match.to, ...match.cc, ...match.bcc] + const messageParticipants = [...message.from, ...message.to, ...message.cc, ...message.bcc] + let matchEmails = matchParticipants.filter((participant) => { return matchBcc.find(bcc => bcc === participant) }) matchEmails.map((email) => { return email[1] }) - let messageEmails = message.participants.filter((participant) => { + let messageEmails = messageParticipants.filter((participant) => { return messageBcc.find(bcc => bcc === participant) }) messageEmails.map((email) => { @@ -125,7 +127,6 @@ function matchThread({db, accountId, message}) { return thread } return Thread.create({ - subject: message.subject, cleanedSubject: cleanSubject(message.subject), }) }) @@ -138,7 +139,6 @@ function matchThread({db, accountId, message}) { return thread } return Thread.create({ - subject: message.subject, cleanedSubject: cleanSubject(message.subject), }) }) @@ -148,15 +148,21 @@ function addMessageToThread({db, accountId, message}) { const {Thread} = db // Check for Gmail's own thread ID if (message.headers['X-GM-THRID']) { - return Thread.find({where: {threadId: message.headers['X-GM-THRID']}}) + const thread = Thread.find({where: {threadId: message.headers['X-GM-THRID']}}) + if (thread) { + return thread + } + return Thread.create({ + cleanedSubject: cleanSubject(message.subject), + threadId: message.headers['X-GM-THRID'], + }) } return matchThread({db, accountId, message}) .then((thread) => (thread)) } -function processMessage({message, accountId}) { - return DatabaseConnector.forAccount(accountId) - .then((db) => addMessageToThread({db, accountId, message})) +function processMessage({db, accountId, message}) { + return addMessageToThread({db, accountId, message}) .then((thread) => { thread.addMessage(message) message.setThread(thread) diff --git a/packages/nylas-message-processor/spec/fixtures/thread.js b/packages/nylas-message-processor/spec/fixtures/thread.js new file mode 100644 index 000000000..cf4f9768a --- /dev/null +++ b/packages/nylas-message-processor/spec/fixtures/thread.js @@ -0,0 +1,94 @@ +export const message = { + id: 1, + subject: "Loved your work and interests", + body: "Hi Jackie,
While browsing Nylas themes, I stumbled upon your website and looked at your work. 
Great work on projects, nice to see your multidisciplinary interests :)

Thanks, 
Sagar Sutar
thesagarsutar.me
", + headers: { + "Delivered-To": "jackiehluo@gmail.com", + "Received": `by 10.107.182.215 with SMTP id g206csp311103iof; + Fri, 17 Jun 2016 09:38:45 -0700 (PDT)`, + "X-Received": `by 10.66.16.133 with SMTP id g5mr1799805pad.145.1466181525915; + Fri, 17 Jun 2016 09:38:45 -0700 (PDT)`, + "Return-Path": "", + "Received": `from mail-pf0-f174.google.com (mail-pf0-f174.google.com. + [209.85.192.174]) + by mx.google.com with ESMTPS id n6si15649421pav.242.2016.06.17.09.38.45 + for + (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); + Fri, 17 Jun 2016 09:38:45 -0700 (PDT)`, + "Received-SPF": `pass (google.com: domain of sagy26.1991@gmail.com + designates 209.85.192.174 as permitted sender) client-ip=209.85.192.174;`, + "Authentication-Results": `mx.google.com; + spf=pass (google.com: domain of sagy26.1991@gmail.com designates + 209.85.192.174 as permitted sender) smtp.mailfrom=sagy26.1991@gmail.com`, + "Received": `by mail-pf0-f174.google.com with SMTP id i123so25772868pfg.0 + for ; Fri, 17 Jun 2016 09:38:45 -0700 (PDT)`, + "X-Google-DKIM-Signature": `v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20130820; + h=x-gm-message-state:date:user-agent:message-id:to:from:subject + :mime-version; + bh=to3fCB9g4R6V18kpAAKSAlUeTC+N0rg4JckFbiaILA4=; + b=WfI5viTYPjviUur9Bd2rJQfpHxIm2xYRdxrN64bJGuX0TQlb7p8bDvCBNNhY3mTXJx + lsQzRX9RA4FMuDk0oz0mpviWtkpkZsDeyjpSmA+ONcPgdyPAezzPDvSWRzMZY21fiHxS + hr4I5AeFKesGcbvwtJu+S0fMGhdveC8E35oTA010Xfave6Xd55qGXy7hW+4xCfvIesy4 + 01oOaXWDmLHqixKO3SXwmGCcDzqn/IKXhB7UXkF0efSTwh8yid6v9iXdW+ovJ2qg9peI + HSnPIilYk8SaKoPdGDgYZykfUIgNrSugtK/vvGG2aN+9lhURxPfzhniWdNqdsgR7G4E7 + 7XqA==`, + "X-Gm-Message-State": "ALyK8tIf7XyYaylyVf0qjzh8rhYz3rj/VQYaNLDjVq5ESH19ioJIgW7o9FbghP+wFYrBuw==", + "X-Received": `by 10.98.111.138 with SMTP id k132mr3246291pfc.105.1466181525186; + Fri, 17 Jun 2016 09:38:45 -0700 (PDT)`, + "Return-Path": "", + "Received": `from [127.0.0.1] (ec2-52-36-99-221.us-west-2.compute.amazonaws.com. [52.36.99.221]) + by smtp.gmail.com with ESMTPSA id d69sm64179062pfj.31.2016.06.17.09.38.44 + for + (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); + Fri, 17 Jun 2016 09:38:44 -0700 (PDT)`, + "Date": "Fri, 17 Jun 2016 09:38:44 -0700 (PDT)", + "User-Agent": "NylasMailer/0.4", + "Message-Id": "<82y7eq1ipmadaxwcy6kr072bw-2147483647@mailer.nylas.com>", + "X-Inbox-Id": "82y7eq1ipmadaxwcy6kr072bw-2147483647", + }, + from: [{ + name: "Sagar Sutar", + email: "", + }], + to: [{ + name: "jackiehluo@gmail.com", + email: "", + }], + cc: [], + bcc: [], + messageId: "<82y7eq1ipmadaxwcy6kr072bw-2147483647@mailer.nylas.com>", + snippet: "Hi Jackie, While browsing Nylas themes, I stumbled upon your website and looked at your work. Great ", + setThread: (thread) => { + message.thread = thread.id + }, +} + +export const reply = { + id: 2, + subject: "Re: Loved your work and interests", + body: "Sagar,

Aw, glad to hear it! Thanks for getting in touch!

Jackie Luo
Software Engineer, Nylas

On Jun 17 2016, at 9:38 am, Sagar Sutar <sagar_s@nid.edu> wrote:
Hi Jackie,
While browsing Nylas themes, I stumbled upon your website and looked at your work. 
Great work on projects, nice to see your multidisciplinary interests :)

Thanks, 
Sagar Sutar
thesagarsutar.me
", + headers: { + "Date": "Fri, 17 Jun 2016 18:20:47 +0000", + "References": "<82y7eq1ipmadaxwcy6kr072bw-2147483647@mailer.nylas.com>", + "In-Reply-To": "<82y7eq1ipmadaxwcy6kr072bw-2147483647@mailer.nylas.com>", + "User-Agent": "NylasMailer/0.4", + "Message-Id": "", + "X-Inbox-Id": "cq08iqwatp00kai4qnff7zbaj-2147483647", + }, + from: [{ + name: "Jackie Luo", + email: "", + }], + to: [{ + name: "Sagar Sutar", + email: "", + }], + cc: [], + bcc: [], + messageId: "", + snippet: "Sagar, Aw, glad to hear it! Thanks for getting in touch! Jackie Luo Software Engineer, Nylas", + setThread: (thread) => { + reply.thread = thread.id + }, +} diff --git a/packages/nylas-message-processor/spec/threading-spec.js b/packages/nylas-message-processor/spec/threading-spec.js new file mode 100644 index 000000000..74f1d56f2 --- /dev/null +++ b/packages/nylas-message-processor/spec/threading-spec.js @@ -0,0 +1,58 @@ +const path = require('path') +const fs = require('fs') +const {DatabaseConnector} = require('nylas-core') +const {processMessage} = require('../processors/threading') + +const BASE_PATH = path.join(__dirname, 'fixtures') + + +it('adds the message to the thread', (done) => { + const {message, reply} = require(`${BASE_PATH}/thread`) + const accountId = 'a-1' + const mockDb = { + Thread: { + findAll: () => { + return Promise.resolve([ + { + id: 1, + cleanedSubject: "Loved your work and interests", + messages: [message], + }]) + }, + find: () => { + return Promise.resolve(null) + }, + create: (thread) => { + thread.id = 1 + thread.addMessage = (message) => { + if (thread.messages) { + thread.messages.push(message.id) + } else { + thread.messages = [message.id] + } + } + return Promise.resolve(thread) + } + }, + Message: { + findAll: () => { + return Promise.resolve([message, reply]) + }, + find: () => { + return Promise.resolve(reply) + }, + create: (message) => { + message.setThread = (thread) => { + console.log("setting") + message.thread = thread.id + } + return Promise.resolve(message) + } + } + } + + processMessage({db: mockDb, message: reply, accountId}).then((processed) => { + expect(processed.thread).toBe(1) + done() + }) +}) diff --git a/packages/nylas-sync/sync-process-manager.js b/packages/nylas-sync/sync-process-manager.js index 9a470c38d..76f29a393 100644 --- a/packages/nylas-sync/sync-process-manager.js +++ b/packages/nylas-sync/sync-process-manager.js @@ -63,7 +63,7 @@ class SyncProcessManager { client.setAsync(key, Date.now()).then(() => client.expireAsync(key, HEARTBEAT_EXPIRES) ).then(() => - console.log("ProcessManager: ❤") + console.log("ProcessManager: 💘") ) }