feat: add migration for table & checklists

This commit is contained in:
thecodrr
2021-12-28 14:50:04 +05:00
parent d16a4abfcc
commit 3353d2235e
3 changed files with 107 additions and 53 deletions

View File

@@ -0,0 +1 @@
{"version":5.2,"type":"web","date":1640684511432,"data":{"069b671dd48576dff9157120":{"id":"069b671dd48576dff9157120","contentId":"8454da84dfa427c2f75f70da","type":"note","title":"Table test note","pinned":false,"locked":false,"tags":[],"favorite":false,"dateCreated":1640684417435,"dateEdited":1640684432529,"localOnly":false,"conflicted":false},"8454da84dfa427c2f75f70da":{"noteId":"069b671dd48576dff9157120","id":"8454da84dfa427c2f75f70da","type":"tiny","data":"<table style=\"border-collapse: collapse; width: 100.063%;\" border=\"1\"><tbody><tr><td style=\"width: 34.3648%;\">Hello<br></td><td style=\"width: 34.3648%;\">World<br></td></tr><tr><td style=\"width: 34.3648%;\">My <br></td><td style=\"width: 34.3648%;\">Name<br data-mce-bogus=\"1\"></td></tr></tbody></table>","dateEdited":1640684432525,"dateCreated":1640684426583,"localOnly":false,"persistDateEdited":false},"_uk_@ammarahmed6506+5@gmail.com":{},"_uk_@ammarahmed6506+5@gmail.com@_k":{"iv":{"0":17,"1":27,"2":18,"3":72,"4":98,"5":156,"6":43,"7":0,"8":63,"9":234,"10":35,"11":22},"cipher":{}},"c5f6fa4fef9be04c0f07f80e":{"noteId":"d3a7a9fbd4bb29ca41570c5e","id":"c5f6fa4fef9be04c0f07f80e","type":"tiny","data":"<ul style=\"list-style-type: none;\" class=\"tox-checklist\"><li>Hello<br></li><li class=\"tox-checklist--checked\">world<br data-mce-bogus=\"1\"></li><li class=\"tox-checklist--checked\">123<br data-mce-bogus=\"1\"></li><li>abc<br data-mce-bogus=\"1\"></li></ul><p>test completed.<br data-mce-bogus=\"1\"></p>","dateEdited":1640684464785,"dateCreated":1640684448878,"localOnly":false,"persistDateEdited":false},"content":["8454da84dfa427c2f75f70da","c5f6fa4fef9be04c0f07f80e"],"d3a7a9fbd4bb29ca41570c5e":{"id":"d3a7a9fbd4bb29ca41570c5e","contentId":"c5f6fa4fef9be04c0f07f80e","type":"note","title":"Checklist test","headline":"test completed.","pinned":false,"locked":false,"tags":[],"favorite":false,"dateCreated":1640684443699,"dateEdited":1640684464786,"localOnly":false,"conflicted":false},"hasConflicts":false,"monographs":[],"notes":["069b671dd48576dff9157120","d3a7a9fbd4bb29ca41570c5e"],"settings":{"type":"settings","id":"87a858b33cd6427364d176d4","pins":[],"groupOptions":{},"aliases":{},"dateEdited":0,"dateCreated":0},"token":{"access_token":"9E5F461613022DB4AC77BE5EA46D8AD67069E7361B8F3FC9F9E9C74409E4CA46","expires_in":3600,"token_type":"Bearer","refresh_token":"4489400BF30C61DCA8B84960620F5B01B165A8FE5C537AE4709E5492758F49ED","scope":"IdentityServerApi notesnook.sync offline_access openid","t":1640684404249}},"hash":"7b6bc37e3338f10535486f03ca71e42d","hash_type":"md5"}

View File

@@ -5,6 +5,7 @@ import {
notebookTest, notebookTest,
} from "./utils"; } from "./utils";
import v52Backup from "./__fixtures__/backup.v5.2.json"; import v52Backup from "./__fixtures__/backup.v5.2.json";
import v52BackupCopy from "./__fixtures__/backup.v5.2.copy.json";
beforeEach(() => { beforeEach(() => {
StorageInterface.clear(); StorageInterface.clear();
@@ -64,65 +65,81 @@ test("import tempered backup", () =>
}) })
)); ));
describe.each([["v5.2", v52Backup]])( describe.each([
"testing backup version: %s", ["v5.2", v52Backup],
(version, data) => { ["v5.2 copy", v52BackupCopy],
test(`import ${version} backup`, () => { ])("testing backup version: %s", (version, data) => {
return databaseTest().then(async (db) => { test(`import ${version} backup`, () => {
await db.backup.import(JSON.stringify(data)); return databaseTest().then(async (db) => {
await db.backup.import(JSON.stringify(data));
expect(db.settings.raw.id).toBeDefined(); expect(db.settings.raw.id).toBeDefined();
expect(db.settings.raw.dateModified).toBeDefined(); expect(db.settings.raw.dateModified).toBeDefined();
expect(db.settings.raw.dateEdited).toBeUndefined(); expect(db.settings.raw.dateEdited).toBeUndefined();
expect(
db.notes.all.every((v) => {
const doesNotHaveContent = v.contentId && !v.content;
const doesNotHaveColors = !v.colors && (!v.color || v.color.length);
const hasTopicsInAllNotebooks =
!v.notebooks ||
v.notebooks.every((nb) => !!nb.id && !!nb.topics && !nb.topic);
const hasDateModified = v.dateModified > 0;
return (
doesNotHaveContent &&
!v.notebook &&
hasTopicsInAllNotebooks &&
doesNotHaveColors &&
hasDateModified
);
})
).toBeTruthy();
expect(
db.notebooks.all.every((v) => v.title != null && v.dateModified > 0)
).toBeTruthy();
expect(
db.attachments.all.every((v) => v.dateModified > 0 && !v.dateEdited)
).toBeTruthy();
const allContent = await db.content.all();
expect(
allContent.every((v) => v.type === "tiny" || v.deleted)
).toBeTruthy();
expect(allContent.every((v) => !v.persistDateEdited)).toBeTruthy();
expect(allContent.every((v) => v.dateModified > 0)).toBeTruthy();
expect(
allContent.every(
(v) =>
!v.data.includes("tox-checklist") &&
!v.data.includes("tox-checklist--checked")
)
).toBeTruthy();
const tableContent = allContent.find((a) => a.data.includes("<table"));
if (tableContent)
expect( expect(
db.notes.all.every((v) => { tableContent.data.includes(
const doesNotHaveContent = v.contentId && !v.content; `<div class="table-container" contenteditable="false">`
const doesNotHaveColors = !v.colors && (!v.color || v.color.length); )
const hasTopicsInAllNotebooks = );
!v.notebooks ||
v.notebooks.every((nb) => !!nb.id && !!nb.topics && !nb.topic);
const hasDateModified = v.dateModified > 0;
return (
doesNotHaveContent &&
!v.notebook &&
hasTopicsInAllNotebooks &&
doesNotHaveColors &&
hasDateModified
);
})
).toBeTruthy();
expect(
db.notebooks.all.every((v) => v.title != null && v.dateModified > 0)
).toBeTruthy();
expect(
db.attachments.all.every((v) => v.dateModified > 0 && !v.dateEdited)
).toBeTruthy();
const allContent = await db.content.all();
expect(
allContent.every((v) => v.type === "tiny" || v.deleted)
).toBeTruthy();
expect(allContent.every((v) => !v.persistDateEdited)).toBeTruthy();
expect(allContent.every((v) => v.dateModified > 0)).toBeTruthy();
});
}); });
});
test(`verify indices of ${version} backup`, () => { test(`verify indices of ${version} backup`, () => {
return databaseTest().then(async (db) => { return databaseTest().then(async (db) => {
await db.backup.import(JSON.stringify(data)); await db.backup.import(JSON.stringify(data));
verifyIndex(data, db, "notes", "notes"); verifyIndex(data, db, "notes", "notes");
verifyIndex(data, db, "notebooks", "notebooks"); verifyIndex(data, db, "notebooks", "notebooks");
verifyIndex(data, db, "content", "content"); verifyIndex(data, db, "content", "content");
verifyIndex(data, db, "attachments", "attachments"); verifyIndex(data, db, "attachments", "attachments");
// verifyIndex(data, db, "trash", "trash"); // verifyIndex(data, db, "trash", "trash");
});
}); });
} });
); });
function verifyIndex(backup, db, backupCollection, collection) { function verifyIndex(backup, db, backupCollection, collection) {
if (!backup.data[backupCollection]) return; if (!backup.data[backupCollection]) return;

View File

@@ -1,3 +1,5 @@
import { parseHTML } from "./utils/html-parser";
export const migrations = { export const migrations = {
5.0: {}, 5.0: {},
5.1: {}, 5.1: {},
@@ -7,7 +9,14 @@ export const migrations = {
tag: replaceDateEditedWithDateModified(true), tag: replaceDateEditedWithDateModified(true),
attachment: replaceDateEditedWithDateModified(true), attachment: replaceDateEditedWithDateModified(true),
trash: replaceDateEditedWithDateModified(), trash: replaceDateEditedWithDateModified(),
tiny: replaceDateEditedWithDateModified(), tiny: (item) => {
item = replaceDateEditedWithDateModified()(item);
if (!item.data || item.data.iv) return item;
item.data = removeToxClassFromChecklist(wrapTablesWithDiv(item.data));
return item;
},
settings: replaceDateEditedWithDateModified(true), settings: replaceDateEditedWithDateModified(true),
}, },
5.3: { 5.3: {
@@ -29,3 +38,30 @@ function replaceDateEditedWithDateModified(removeDateEditedProperty = false) {
return item; return item;
}; };
} }
function wrapTablesWithDiv(html) {
const document = parseHTML(html);
const tables = document.getElementsByTagName("table");
for (let table of tables) {
table.setAttribute("contenteditable", "true");
table.replaceWith(
`<div class="table-container" contenteditable="false">${table.outerHTML}</div>`
);
}
return document.outerHTML || document.body.innerHTML;
}
function removeToxClassFromChecklist(html) {
const document = parseHTML(html);
const checklists = document.querySelectorAll(
".tox-checklist,.tox-checklist--checked"
);
for (let item of checklists) {
if (item.classList.contains("tox-checklist--checked"))
item.classList.replace("tox-checklist--checked", "checked");
else if (item.classList.contains("tox-checklist"))
item.classList.replace("tox-checklist", "checklist");
}
return document.outerHTML || document.body.innerHTML;
}