Message schema 6: Change classification of media and documents
For an easier implementation, we change our original definition of `initializeAttachmentMetadata`. This means we have to re-run it marked as version 6 and mark schema version 5 as deprecated as its definition has changed.
This commit is contained in:
parent
f4a5bc9907
commit
16bc1d34c6
4 changed files with 120 additions and 15 deletions
|
@ -25,13 +25,21 @@ const PRIVATE = 'private';
|
||||||
// - Attachments: Write attachment data to disk and store relative path to it.
|
// - Attachments: Write attachment data to disk and store relative path to it.
|
||||||
// Version 4
|
// Version 4
|
||||||
// - Quotes: Write thumbnail data to disk and store relative path to it.
|
// - Quotes: Write thumbnail data to disk and store relative path to it.
|
||||||
// Version 5
|
// Version 5 (deprecated)
|
||||||
// - Attachments: Track number and kind of attachments for media gallery
|
// - Attachments: Track number and kind of attachments for media gallery
|
||||||
// - `hasAttachments?: 1 | 0`
|
// - `hasAttachments?: 1 | 0`
|
||||||
// - `hasVisualMediaAttachments?: 1 | undefined` (for media gallery ‘Media’ view)
|
// - `hasVisualMediaAttachments?: 1 | undefined` (for media gallery ‘Media’ view)
|
||||||
// - `hasFileAttachments?: 1 | undefined` (for media gallery ‘Documents’ view)
|
// - `hasFileAttachments?: 1 | undefined` (for media gallery ‘Documents’ view)
|
||||||
|
// - IMPORTANT: Version 7 changes the classification of visual media and files.
|
||||||
|
// Therefore version 5 is considered deprecated. For an easier implementation,
|
||||||
|
// new files have the same classification in version 5 as in version 7.
|
||||||
// Version 6
|
// Version 6
|
||||||
// - Contact: Write contact avatar to disk, ensure contact data is well-formed
|
// - Contact: Write contact avatar to disk, ensure contact data is well-formed
|
||||||
|
// Version 7 (supersedes attachment classification in version 5)
|
||||||
|
// - Attachments: Update classification for:
|
||||||
|
// - `hasVisualMediaAttachments`: Include all images and video regardless of
|
||||||
|
// whether Chromium can render it or not.
|
||||||
|
// - `hasFileAttachments`: Exclude voice messages.
|
||||||
|
|
||||||
const INITIAL_SCHEMA_VERSION = 0;
|
const INITIAL_SCHEMA_VERSION = 0;
|
||||||
|
|
||||||
|
@ -228,6 +236,10 @@ const toVersion6 = exports._withSchemaVersion(
|
||||||
Contact.parseAndWriteAvatar(Attachment.migrateDataToFileSystem)
|
Contact.parseAndWriteAvatar(Attachment.migrateDataToFileSystem)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
// IMPORTANT: We’ve updated our definition of `initializeAttachmentMetadata`, so
|
||||||
|
// we need to run it again on existing items that have previously been incorrectly
|
||||||
|
// classified:
|
||||||
|
const toVersion7 = exports._withSchemaVersion(7, initializeAttachmentMetadata);
|
||||||
|
|
||||||
const VERSIONS = [
|
const VERSIONS = [
|
||||||
toVersion0,
|
toVersion0,
|
||||||
|
@ -236,6 +248,8 @@ const VERSIONS = [
|
||||||
toVersion3,
|
toVersion3,
|
||||||
toVersion4,
|
toVersion4,
|
||||||
toVersion5,
|
toVersion5,
|
||||||
|
toVersion6,
|
||||||
|
toVersion7,
|
||||||
];
|
];
|
||||||
exports.CURRENT_SCHEMA_VERSION = VERSIONS.length - 1;
|
exports.CURRENT_SCHEMA_VERSION = VERSIONS.length - 1;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ const { assert } = require('chai');
|
||||||
const sinon = require('sinon');
|
const sinon = require('sinon');
|
||||||
|
|
||||||
const Message = require('../../../js/modules/types/message');
|
const Message = require('../../../js/modules/types/message');
|
||||||
|
const { SignalService } = require('../../../ts/protobuf');
|
||||||
const {
|
const {
|
||||||
stringToArrayBuffer,
|
stringToArrayBuffer,
|
||||||
} = require('../../../js/modules/string_to_array_buffer');
|
} = require('../../../js/modules/string_to_array_buffer');
|
||||||
|
@ -242,7 +243,8 @@ describe('Message', () => {
|
||||||
const input = {
|
const input = {
|
||||||
attachments: [
|
attachments: [
|
||||||
{
|
{
|
||||||
contentType: 'application/json',
|
contentType: 'audio/aac',
|
||||||
|
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
|
||||||
data: stringToArrayBuffer('It’s easy if you try'),
|
data: stringToArrayBuffer('It’s easy if you try'),
|
||||||
fileName: 'test\u202Dfig.exe',
|
fileName: 'test\u202Dfig.exe',
|
||||||
size: 1111,
|
size: 1111,
|
||||||
|
@ -253,7 +255,8 @@ describe('Message', () => {
|
||||||
const expected = {
|
const expected = {
|
||||||
attachments: [
|
attachments: [
|
||||||
{
|
{
|
||||||
contentType: 'application/json',
|
contentType: 'audio/aac',
|
||||||
|
flags: 1,
|
||||||
path: 'abc/abcdefg',
|
path: 'abc/abcdefg',
|
||||||
fileName: 'test\uFFFDfig.exe',
|
fileName: 'test\uFFFDfig.exe',
|
||||||
size: 1111,
|
size: 1111,
|
||||||
|
@ -261,7 +264,7 @@ describe('Message', () => {
|
||||||
],
|
],
|
||||||
hasAttachments: 1,
|
hasAttachments: 1,
|
||||||
hasVisualMediaAttachments: undefined,
|
hasVisualMediaAttachments: undefined,
|
||||||
hasFileAttachments: 1,
|
hasFileAttachments: undefined,
|
||||||
schemaVersion: Message.CURRENT_SCHEMA_VERSION,
|
schemaVersion: Message.CURRENT_SCHEMA_VERSION,
|
||||||
contact: [],
|
contact: [],
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,13 +3,14 @@ import { assert } from 'chai';
|
||||||
|
|
||||||
import * as Message from '../../../../ts/types/message/initializeAttachmentMetadata';
|
import * as Message from '../../../../ts/types/message/initializeAttachmentMetadata';
|
||||||
import { IncomingMessage } from '../../../../ts/types/Message';
|
import { IncomingMessage } from '../../../../ts/types/Message';
|
||||||
|
import { SignalService } from '../../../../ts/protobuf';
|
||||||
import * as MIME from '../../../../ts/types/MIME';
|
import * as MIME from '../../../../ts/types/MIME';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { stringToArrayBuffer } from '../../../../js/modules/string_to_array_buffer';
|
import { stringToArrayBuffer } from '../../../../js/modules/string_to_array_buffer';
|
||||||
|
|
||||||
describe('Message', () => {
|
describe('Message', () => {
|
||||||
describe('initializeAttachmentMetadata', () => {
|
describe('initializeAttachmentMetadata', () => {
|
||||||
it('should handle visual media attachments', async () => {
|
it('should classify visual media attachments', async () => {
|
||||||
const input: IncomingMessage = {
|
const input: IncomingMessage = {
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
conversationId: 'foo',
|
conversationId: 'foo',
|
||||||
|
@ -49,5 +50,89 @@ describe('Message', () => {
|
||||||
const actual = await Message.initializeAttachmentMetadata(input);
|
const actual = await Message.initializeAttachmentMetadata(input);
|
||||||
assert.deepEqual(actual, expected);
|
assert.deepEqual(actual, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should classify file attachments', async () => {
|
||||||
|
const input: IncomingMessage = {
|
||||||
|
type: 'incoming',
|
||||||
|
conversationId: 'foo',
|
||||||
|
id: '11111111-1111-1111-1111-111111111111',
|
||||||
|
timestamp: 1523317140899,
|
||||||
|
received_at: 1523317140899,
|
||||||
|
sent_at: 1523317140800,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
contentType: MIME.APPLICATION_OCTET_STREAM,
|
||||||
|
data: stringToArrayBuffer('foo'),
|
||||||
|
fileName: 'foo.bin',
|
||||||
|
size: 1111,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const expected: IncomingMessage = {
|
||||||
|
type: 'incoming',
|
||||||
|
conversationId: 'foo',
|
||||||
|
id: '11111111-1111-1111-1111-111111111111',
|
||||||
|
timestamp: 1523317140899,
|
||||||
|
received_at: 1523317140899,
|
||||||
|
sent_at: 1523317140800,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
contentType: MIME.APPLICATION_OCTET_STREAM,
|
||||||
|
data: stringToArrayBuffer('foo'),
|
||||||
|
fileName: 'foo.bin',
|
||||||
|
size: 1111,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hasAttachments: 1,
|
||||||
|
hasVisualMediaAttachments: undefined,
|
||||||
|
hasFileAttachments: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const actual = await Message.initializeAttachmentMetadata(input);
|
||||||
|
assert.deepEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should classify voice message attachments', async () => {
|
||||||
|
const input: IncomingMessage = {
|
||||||
|
type: 'incoming',
|
||||||
|
conversationId: 'foo',
|
||||||
|
id: '11111111-1111-1111-1111-111111111111',
|
||||||
|
timestamp: 1523317140899,
|
||||||
|
received_at: 1523317140899,
|
||||||
|
sent_at: 1523317140800,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
contentType: MIME.AUDIO_AAC,
|
||||||
|
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
|
||||||
|
data: stringToArrayBuffer('foo'),
|
||||||
|
fileName: 'Voice Message.aac',
|
||||||
|
size: 1111,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const expected: IncomingMessage = {
|
||||||
|
type: 'incoming',
|
||||||
|
conversationId: 'foo',
|
||||||
|
id: '11111111-1111-1111-1111-111111111111',
|
||||||
|
timestamp: 1523317140899,
|
||||||
|
received_at: 1523317140899,
|
||||||
|
sent_at: 1523317140800,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
contentType: MIME.AUDIO_AAC,
|
||||||
|
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
|
||||||
|
data: stringToArrayBuffer('foo'),
|
||||||
|
fileName: 'Voice Message.aac',
|
||||||
|
size: 1111,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hasAttachments: 1,
|
||||||
|
hasVisualMediaAttachments: undefined,
|
||||||
|
hasFileAttachments: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const actual = await Message.initializeAttachmentMetadata(input);
|
||||||
|
assert.deepEqual(actual, expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import { partition } from 'lodash';
|
|
||||||
|
|
||||||
import * as Attachment from '../Attachment';
|
import * as Attachment from '../Attachment';
|
||||||
import * as IndexedDB from '../IndexedDB';
|
import * as IndexedDB from '../IndexedDB';
|
||||||
import { Message } from '../Message';
|
import { Message, UserMessage } from '../Message';
|
||||||
|
|
||||||
|
const hasAttachment = (
|
||||||
|
predicate: (value: Attachment.Attachment) => boolean
|
||||||
|
) => (message: UserMessage): IndexedDB.IndexablePresence =>
|
||||||
|
IndexedDB.toIndexablePresence(message.attachments.some(predicate));
|
||||||
|
|
||||||
|
const hasFileAttachment = hasAttachment(Attachment.isFile);
|
||||||
|
const hasVisualMediaAttachment = hasAttachment(Attachment.isVisualMedia);
|
||||||
|
|
||||||
export const initializeAttachmentMetadata = async (
|
export const initializeAttachmentMetadata = async (
|
||||||
message: Message
|
message: Message
|
||||||
|
@ -14,17 +20,14 @@ export const initializeAttachmentMetadata = async (
|
||||||
const hasAttachments = IndexedDB.toIndexableBoolean(
|
const hasAttachments = IndexedDB.toIndexableBoolean(
|
||||||
message.attachments.length > 0
|
message.attachments.length > 0
|
||||||
);
|
);
|
||||||
const [hasVisualMediaAttachments, hasFileAttachments] = partition(
|
|
||||||
message.attachments,
|
const hasFileAttachments = hasFileAttachment(message);
|
||||||
Attachment.isVisualMedia
|
const hasVisualMediaAttachments = hasVisualMediaAttachment(message);
|
||||||
)
|
|
||||||
.map(attachments => attachments.length > 0)
|
|
||||||
.map(IndexedDB.toIndexablePresence);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...message,
|
...message,
|
||||||
hasAttachments,
|
hasAttachments,
|
||||||
hasVisualMediaAttachments,
|
|
||||||
hasFileAttachments,
|
hasFileAttachments,
|
||||||
|
hasVisualMediaAttachments,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue