[local-sync, iso-core] feat(send): add finishing touches to gmail multi-send

Delete the sent messages that gmail automatically creates and save our
generic form of the draft as a sent message.
This commit is contained in:
Halla Moore 2016-12-06 11:34:30 -08:00
parent 1a24840062
commit e785d73bdc
8 changed files with 87 additions and 42 deletions

View file

@ -1,4 +1,5 @@
const _ = require('underscore');
const PromiseUtils = require('./promise-utils')
const {
IMAPConnectionNotReadyError,
@ -173,6 +174,24 @@ class IMAPBox {
return this._conn._imap.delLabelsAsync(range, labels)
}
append(rawMime, options) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::append`)
}
return PromiseUtils.promisify(this._conn._imap.append).call(
this._conn._imap, rawMime, options
);
}
search(criteria) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::search`)
}
return PromiseUtils.promisify(this._conn._imap.search).call(
this._conn._imap, criteria
);
}
closeBox({expunge = true} = {}) {
if (!this._conn._imap) {
throw new IMAPConnectionNotReadyError(`IMAPBox::closeBox`)

View file

@ -168,10 +168,10 @@ module.exports = (server) => {
// gmail creates sent messages for each one, go through and delete them
if (account.provider === 'gmail') {
try {
// TODO: use type: "PermananentDeleteMessage" once it's fully implemented
await db.SyncbackRequest.create({
type: "DeleteMessage",
props: { messageId: draft.id },
accountId: account.id,
type: "DeleteSentMessage",
props: { messageId: `${draft.id}@nylas.com` },
});
} catch (err) {
// Even if this fails, we need to finish the multi-send session,
@ -185,7 +185,7 @@ module.exports = (server) => {
await db.SyncbackRequest.create({
accountId: account.id,
type: "SaveSentMessage",
props: {rawMime},
props: {rawMime, messageId: `${draft.id}@nylas.com`},
});
await (draft.isSent = true);

View file

@ -57,6 +57,7 @@ class SendmailClient {
}
msgData.subject = draft.subject;
msgData.html = draft.body;
msgData.messageId = `${draft.id}@nylas.com`;
// TODO: attachments
@ -69,18 +70,17 @@ class SendmailClient {
msgData.headers = draft.headers;
msgData.headers['User-Agent'] = `NylasMailer-K2`
// TODO: do we want to set messageId or date?
return msgData;
}
async buildMime(draft) {
const builder = mailcomposer(this._draftToMsgData(draft))
return new Promise((resolve, reject) => {
const mimeNode = await (new Promise((resolve, reject) => {
builder.build((error, result) => {
error ? reject(error) : resolve(result)
})
})
}));
return mimeNode.toString('ascii')
}
async send(draft) {

View file

@ -56,6 +56,8 @@ class SyncbackTaskFactory {
Task = require('./syncback_tasks/delete-message.imap'); break;
case "SaveSentMessage":
Task = require('./syncback_tasks/save-sent-message.imap'); break;
case "DeleteSentMessage":
Task = require('./syncback_tasks/delete-sent-message.gmail'); break;
default:
throw new Error(`Task type not defined in syncback-task-factory: ${syncbackRequest.type}`)
}

View file

@ -6,13 +6,10 @@ class DeleteMessageIMAP extends SyncbackTask {
return `DeleteMessage`;
}
run(db, imap) {
async run(db, imap) {
const messageId = this.syncbackRequestObject().props.messageId
return TaskHelpers.openMessageBox({messageId, db, imap})
.then(({box, message}) => {
return box.addFlags(message.folderImapUID, 'DELETED')
})
const {box, message} = await TaskHelpers.openMessageBox({messageId, db, imap})
return box.addFlags(message.folderImapUID, ['DELETED'])
}
}
module.exports = DeleteMessageIMAP;

View file

@ -0,0 +1,33 @@
const SyncbackTask = require('./syncback-task')
class DeleteSentMessageGMAIL extends SyncbackTask {
description() {
return `DeleteSentMessage`;
}
async run(db, imap) {
const {messageId} = this.syncbackRequestObject().props
const trash = await db.Folder.find({where: {role: 'trash'}});
if (!trash) { throw new Error(`Could not find folder with role 'trash'.`) }
const allMail = await db.Folder.find({where: {role: 'all'}});
if (!allMail) { throw new Error(`Could not find folder with role 'all'.`) }
// Move the message from all mail to trash and then delete it from there
const steps = [
{folder: allMail, deleteFn: (box, uid) => box.moveFromBox(uid, trash.name)},
{folder: trash, deleteFn: (box, uid) => box.addFlags(uid, 'DELETED')},
]
for (const {folder, deleteFn} of steps) {
const box = await imap.openBox(folder.name);
const uids = await box.search([['HEADER', 'Message-ID', messageId]])
for (const uid of uids) {
await deleteFn(box, uid);
}
box.closeBox();
}
}
}
module.exports = DeleteSentMessageGMAIL;

View file

@ -1,24 +0,0 @@
const SyncbackTask = require('./syncback-task')
class PermanentlyDeleteMessageIMAP extends SyncbackTask {
description() {
return `PermanentlyDeleteMessage`;
}
async run(db, imap) {
const messageId = this.syncbackRequestObject().props.messageId
const message = await db.Message.findById(messageId);
const folder = await db.Folder.findById(message.folderId);
const box = await imap.openBox(folder.name);
const result = await box.addFlags(message.folderImapUID, 'DELETED');
return result;
// TODO: We need to also delete the message from the trash
// if (folder.role === 'trash') { return result; }
//
// const trash = await db.Folder.find({where: {role: 'trash'}});
// const trashBox = await imap.openBox(trash.name);
// return await trashBox.addFlags(message.folderImapUID, 'DELETED');
}
}
module.exports = PermanentlyDeleteMessageIMAP;

View file

@ -6,10 +6,28 @@ class SaveSentMessageIMAP extends SyncbackTask {
}
async run(db, imap) {
// TODO: gmail doesn't have a sent folder
const folder = await db.Folder.find({where: {role: 'sent'}});
const box = await imap.openBox(folder.name);
return box.append(this.syncbackRequestObject().props.rawMime);
const {rawMime, messageId} = this.syncbackRequestObject().props;
// Non-gmail
const sentFolder = await db.Folder.find({where: {role: 'sent'}});
if (sentFolder) {
const box = await imap.openBox(sentFolder.name);
return box.append(rawMime);
}
// Gmail, we need to add the message to all mail and add the sent label
const sentLabel = await db.Label.find({where: {role: 'sent'}});
const allMail = await db.Folder.find({where: {role: 'all'}});
if (sentLabel && allMail) {
let box = await imap.openBox(allMail.name);
await box.append(rawMime, {flags: 'SEEN'})
const uids = await box.search([['HEADER', 'Message-ID', messageId]])
// There should only be one uid in the array
return box.setLabels(uids[0], '\\Sent');
}
throw new Error('Could not save message to sent folder.')
}
}
module.exports = SaveSentMessageIMAP;