All: Fixes #597: Also import sub-notebooks when importing JEX data

pull/607/head
Laurent Cozic 2018-06-10 19:15:40 +01:00
parent 0d9f703c75
commit ab9675544c
4 changed files with 89 additions and 16 deletions

View File

@ -13,6 +13,8 @@ const ArrayUtils = require('lib/ArrayUtils');
const ObjectUtils = require('lib/ObjectUtils');
const { shim } = require('lib/shim.js');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
@ -249,6 +251,41 @@ describe('services_InteropService', function() {
expect(folder2.title).toBe('folder1');
}));
it('should export and import folder and its sub-folders', asyncTest(async () => {
const service = new InteropService();
const filePath = exportDir() + '/test.jex';
let folder1 = await Folder.save({ title: "folder1" });
let folder2 = await Folder.save({ title: "folder2", parent_id: folder1.id });
let folder3 = await Folder.save({ title: "folder3", parent_id: folder2.id });
let folder4 = await Folder.save({ title: "folder4", parent_id: folder2.id });
let note1 = await Note.save({ title: 'ma note', parent_id: folder4.id });
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
await Note.delete(note1.id);
await Folder.delete(folder1.id);
await Folder.delete(folder2.id);
await Folder.delete(folder3.id);
await Folder.delete(folder4.id);
await service.import({ path: filePath });
expect(await Note.count()).toBe(1);
expect(await Folder.count()).toBe(4);
let folder1_2 = await Folder.loadByTitle('folder1');
let folder2_2 = await Folder.loadByTitle('folder2');
let folder3_2 = await Folder.loadByTitle('folder3');
let folder4_2 = await Folder.loadByTitle('folder4');
let note1_2 = await Note.loadByTitle('ma note');
expect(folder2_2.parent_id).toBe(folder1_2.id);
expect(folder3_2.parent_id).toBe(folder2_2.id);
expect(folder4_2.parent_id).toBe(folder2_2.id);
expect(note1_2.parent_id).toBe(folder4_2.id);
}));
it('should export and import links to notes', asyncTest(async () => {
const service = new InteropService();
const filePath = exportDir() + '/test.jex';

View File

@ -127,6 +127,23 @@ class Folder extends BaseItem {
return output;
}
static async childrenIds(folderId, recursive) {
if (recursive === false) throw new Error('Not implemented');
const folders = await this.db().selectAll('SELECT id FROM folders WHERE parent_id = ?', [folderId]);
let output = [];
for (let i = 0; i < folders.length; i++) {
const f = folders[i];
output.push(f.id);
const subChildrenIds = await this.childrenIds(f.id, true);
output = output.concat(subChildrenIds);
}
return output;
}
static async allAsTree(options = null) {
const all = await this.all(options);

View File

@ -157,7 +157,7 @@ class InteropService {
async export(options) {
const exportPath = options.path ? options.path : null;
const sourceFolderIds = options.sourceFolderIds ? options.sourceFolderIds : [];
let sourceFolderIds = options.sourceFolderIds ? options.sourceFolderIds : [];
const sourceNoteIds = options.sourceNoteIds ? options.sourceNoteIds : [];
const exportFormat = options.format ? options.format : 'jex';
const result = { warnings: [] }
@ -174,6 +174,14 @@ class InteropService {
let resourceIds = [];
const folderIds = await Folder.allIds();
let fullSourceFolderIds = sourceFolderIds.slice();
for (let i = 0; i < sourceFolderIds.length; i++) {
const id = sourceFolderIds[i];
const childrenIds = await Folder.childrenIds(id);
fullSourceFolderIds = fullSourceFolderIds.concat(childrenIds);
}
sourceFolderIds = fullSourceFolderIds;
for (let folderIndex = 0; folderIndex < folderIds.length; folderIndex++) {
const folderId = folderIds[folderIndex];
if (sourceFolderIds.length && sourceFolderIds.indexOf(folderId) < 0) continue;

View File

@ -56,6 +56,25 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
return defaultFolder_;
}
const setFolderToImportTo = async (itemParentId) => {
// Logic is a bit complex here:
// - If a destination folder was specified, move the note to it.
// - Otherwise, if the associated folder exists, use this.
// - If it doesn't exist, use the default folder. This is the case for example when importing JEX archives that contain only one or more notes, but no folder.
const itemParentExists = folderExists(stats, itemParentId);
if (!itemIdMap[itemParentId]) {
if (destinationFolderId) {
itemIdMap[itemParentId] = destinationFolderId;
} else if (!itemParentExists) {
const parentFolder = await defaultFolder();
itemIdMap[itemParentId] = parentFolder.id;
} else {
itemIdMap[itemParentId] = uuid.create();
}
}
}
for (let i = 0; i < stats.length; i++) {
const stat = stats[i];
if (stat.isDirectory()) continue;
@ -70,23 +89,10 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
if (itemType === BaseModel.TYPE_NOTE) {
// Logic is a bit complex here:
// - If a destination folder was specified, move the note to it.
// - Otherwise, if the associated folder exists, use this.
// - If it doesn't exist, use the default folder. This is the case for example when importing JEX archives that contain only one or more notes, but no folder.
if (!itemIdMap[item.parent_id]) {
if (destinationFolderId) {
itemIdMap[item.parent_id] = destinationFolderId;
} else if (!folderExists(stats, item.parent_id)) {
const parentFolder = await defaultFolder();
itemIdMap[item.parent_id] = parentFolder.id;
} else {
itemIdMap[item.parent_id] = uuid.create();
}
}
await setFolderToImportTo(item.parent_id);
if (!itemIdMap[item.id]) itemIdMap[item.id] = uuid.create();
item.id = itemIdMap[item.id]; //noteId;
item.id = itemIdMap[item.id];
item.parent_id = itemIdMap[item.parent_id];
item.body = await replaceLinkedItemIds(item.body);
} else if (itemType === BaseModel.TYPE_FOLDER) {
@ -95,6 +101,11 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
if (!itemIdMap[item.id]) itemIdMap[item.id] = uuid.create();
item.id = itemIdMap[item.id];
item.title = await Folder.findUniqueFolderTitle(item.title);
if (item.parent_id) {
await setFolderToImportTo(item.parent_id);
item.parent_id = itemIdMap[item.parent_id];
}
} else if (itemType === BaseModel.TYPE_RESOURCE) {
if (!itemIdMap[item.id]) itemIdMap[item.id] = uuid.create();
item.id = itemIdMap[item.id];