Quotes: The full pipeline into the database
1. MessageReceiver always pulls down thumbnails included in quotes 2. Message.upgradeSchema has a new schema that puts all thumbnails on disk just like happens with full attachments. 3. handleDataMessage pipes quote from dataMessage into the final message destined for the database
This commit is contained in:
parent
e69586200a
commit
054d3887a1
4 changed files with 129 additions and 6 deletions
|
@ -447,6 +447,7 @@
|
|||
body : dataMessage.body,
|
||||
conversationId : conversation.id,
|
||||
attachments : dataMessage.attachments,
|
||||
quote : dataMessage.quote,
|
||||
decrypted_at : now,
|
||||
flags : dataMessage.flags,
|
||||
errors : []
|
||||
|
|
|
@ -26,7 +26,7 @@ const INITIAL_SCHEMA_VERSION = 0;
|
|||
// add more upgrade steps, we could design a pipeline that does this
|
||||
// incrementally, e.g. from version 0 / unknown -> 1, 1 --> 2, etc., similar to
|
||||
// how we do database migrations:
|
||||
exports.CURRENT_SCHEMA_VERSION = 3;
|
||||
exports.CURRENT_SCHEMA_VERSION = 4;
|
||||
|
||||
|
||||
// Public API
|
||||
|
@ -149,6 +149,26 @@ exports._mapAttachments = upgradeAttachment => async (message, context) => {
|
|||
return Object.assign({}, message, { attachments });
|
||||
};
|
||||
|
||||
// _mapQuotedAttachments :: (QuotedAttachment -> Promise QuotedAttachment) ->
|
||||
// (Message, Context) ->
|
||||
//
|
||||
exports._mapQuotedAttachments = upgradeAttachment => async (message, context) => {
|
||||
if (!message.quote) {
|
||||
return message;
|
||||
}
|
||||
|
||||
const upgradeWithContext = attachment =>
|
||||
upgradeAttachment(attachment, context);
|
||||
const quotedAttachments = (message.quote && message.quote.attachments) || [];
|
||||
|
||||
const attachments = await Promise.all(quotedAttachments.map(upgradeWithContext));
|
||||
return Object.assign({}, message, {
|
||||
quote: Object.assign({}, message.quote, {
|
||||
attachments,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const toVersion0 = async message =>
|
||||
exports.initializeSchemaVersion(message);
|
||||
|
||||
|
@ -164,17 +184,29 @@ const toVersion3 = exports._withSchemaVersion(
|
|||
3,
|
||||
exports._mapAttachments(Attachment.migrateDataToFileSystem)
|
||||
);
|
||||
const toVersion4 = exports._withSchemaVersion(
|
||||
4,
|
||||
exports._mapQuotedAttachments(Attachment.migrateDataToFileSystem)
|
||||
);
|
||||
|
||||
// UpgradeStep
|
||||
exports.upgradeSchema = async (message, { writeNewAttachmentData } = {}) => {
|
||||
exports.upgradeSchema = async (rawMessage, { writeNewAttachmentData } = {}) => {
|
||||
if (!isFunction(writeNewAttachmentData)) {
|
||||
throw new TypeError('`context.writeNewAttachmentData` is required');
|
||||
}
|
||||
|
||||
return toVersion3(
|
||||
await toVersion2(await toVersion1(await toVersion0(message))),
|
||||
{ writeNewAttachmentData }
|
||||
);
|
||||
let message = rawMessage;
|
||||
const versions = [toVersion0, toVersion1, toVersion2, toVersion3, toVersion4];
|
||||
|
||||
for (let i = 0, max = versions.length; i < max; i += 1) {
|
||||
const currentVersion = versions[i];
|
||||
// We really do want this intra-loop await because this is a chained async action,
|
||||
// each step dependent on the previous
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
message = await currentVersion(message, { writeNewAttachmentData });
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
|
||||
exports.createAttachmentLoader = (loadAttachmentData) => {
|
||||
|
|
|
@ -1006,6 +1006,18 @@ MessageReceiver.prototype.extend({
|
|||
const attachment = decrypted.attachments[i];
|
||||
promises.push(this.handleAttachment(attachment));
|
||||
}
|
||||
|
||||
if (decrypted.quote && decrypted.quote.attachments) {
|
||||
const { attachments } = decrypted.quote;
|
||||
|
||||
for (let i = 0, max = attachments.length; i < max; i += 1) {
|
||||
const attachment = attachments[i];
|
||||
if (attachment.thumbnail) {
|
||||
promises.push(this.handleAttachment(attachment.thumbnail));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(() => decrypted);
|
||||
/* eslint-enable no-bitwise, no-param-reassign */
|
||||
},
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const { assert } = require('chai');
|
||||
const sinon = require('sinon');
|
||||
|
||||
const Message = require('../../../js/modules/types/message');
|
||||
const { stringToArrayBuffer } = require('../../../js/modules/string_to_array_buffer');
|
||||
|
@ -308,4 +309,81 @@ describe('Message', () => {
|
|||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_mapQuotedAttachments', () => {
|
||||
it('handles message with no quote', async () => {
|
||||
const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called"));
|
||||
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
||||
|
||||
const message = {
|
||||
body: 'hey there!',
|
||||
};
|
||||
const result = await upgradeVersion(message);
|
||||
assert.deepEqual(result, message);
|
||||
});
|
||||
|
||||
it('handles quote with no attachments', async () => {
|
||||
const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called"));
|
||||
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
||||
|
||||
const message = {
|
||||
body: 'hey there!',
|
||||
quote: {
|
||||
text: 'hey!',
|
||||
},
|
||||
};
|
||||
const expected = {
|
||||
body: 'hey there!',
|
||||
quote: {
|
||||
text: 'hey!',
|
||||
attachments: [],
|
||||
},
|
||||
};
|
||||
const result = await upgradeVersion(message);
|
||||
assert.deepEqual(result, expected);
|
||||
});
|
||||
|
||||
it('handles zero attachments', async () => {
|
||||
const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called"));
|
||||
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
||||
|
||||
const message = {
|
||||
body: 'hey there!',
|
||||
quote: {
|
||||
text: 'hey!',
|
||||
attachments: [],
|
||||
},
|
||||
};
|
||||
const result = await upgradeVersion(message);
|
||||
assert.deepEqual(result, message);
|
||||
});
|
||||
|
||||
it('calls provided async function for each quoted attachment', async () => {
|
||||
const upgradeAttachment = sinon.stub().returns(Promise.resolve({
|
||||
path: '/new/path/on/disk',
|
||||
}));
|
||||
const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment);
|
||||
|
||||
const message = {
|
||||
body: 'hey there!',
|
||||
quote: {
|
||||
text: 'hey!',
|
||||
attachments: [{
|
||||
data: 'data is here',
|
||||
}],
|
||||
},
|
||||
};
|
||||
const expected = {
|
||||
body: 'hey there!',
|
||||
quote: {
|
||||
text: 'hey!',
|
||||
attachments: [{
|
||||
path: '/new/path/on/disk',
|
||||
}],
|
||||
},
|
||||
};
|
||||
const result = await upgradeVersion(message);
|
||||
assert.deepEqual(result, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue