1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-03-03 15:32:30 +02:00

Allow importing and exporting single notes and notebooks

This commit is contained in:
Laurent Cozic 2018-03-01 18:35:17 +00:00
parent 5ba98b4200
commit a078947d6d
3 changed files with 77 additions and 2 deletions

View File

@ -209,4 +209,44 @@ describe('services_InteropService', function() {
expect(fileContentEqual(resourcePath1, resourcePath2)).toBe(true); expect(fileContentEqual(resourcePath1, resourcePath2)).toBe(true);
})); }));
it('should export and import single notes', asyncTest(async () => {
const service = new InteropService();
const filePath = exportDir() + '/test.jex';
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
await service.export({ path: filePath, sourceNoteIds: [note1.id] });
await Note.delete(note1.id);
await Folder.delete(folder1.id);
await service.import({ path: filePath });
expect(await Note.count()).toBe(1);
expect(await Folder.count()).toBe(1);
let folder2 = (await Folder.all())[0];
expect(folder2.title).toBe('test');
}));
it('should export and import single folders', asyncTest(async () => {
const service = new InteropService();
const filePath = exportDir() + '/test.jex';
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
await Note.delete(note1.id);
await Folder.delete(folder1.id);
await service.import({ path: filePath });
expect(await Note.count()).toBe(1);
expect(await Folder.count()).toBe(1);
let folder2 = (await Folder.all())[0];
expect(folder2.title).toBe('folder1');
}));
}); });

View File

@ -36,6 +36,8 @@ class InteropService_Importer_Jex extends InteropService_Importer_Base {
throw e; throw e;
} }
if (!('defaultFolderTitle' in this.options_)) this.options_.defaultFolderTitle = filename(this.sourcePath_);
const importer = new InteropService_Importer_Raw(); const importer = new InteropService_Importer_Raw();
await importer.init(tempDir, this.options_); await importer.init(tempDir, this.options_);
result = await importer.exec(result); result = await importer.exec(result);

View File

@ -14,7 +14,6 @@ const { shim } = require('lib/shim');
const { _ } = require('lib/locale'); const { _ } = require('lib/locale');
const { fileExtension } = require('lib/path-utils'); const { fileExtension } = require('lib/path-utils');
const { uuid } = require('lib/uuid.js'); const { uuid } = require('lib/uuid.js');
const { importEnex } = require('lib/import-enex');
class InteropService_Importer_Raw extends InteropService_Importer_Base { class InteropService_Importer_Raw extends InteropService_Importer_Base {
@ -41,6 +40,25 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
} }
const stats = await shim.fsDriver().readDirStats(this.sourcePath_); const stats = await shim.fsDriver().readDirStats(this.sourcePath_);
const folderExists = function(stats, folderId) {
folderId = folderId.toLowerCase();
for (let i = 0; i < stats.length; i++) {
const stat = stats[i];
const statId = BaseItem.pathToId(stat.path);
if (statId.toLowerCase() === folderId) return true;
}
return false;
}
let defaultFolder_ = null;
const defaultFolder = async () => {
if (defaultFolder_) return defaultFolder_;
const folderTitle = await Folder.findUniqueFolderTitle(this.options_.defaultFolderTitle ? this.options_.defaultFolderTitle : 'Imported');
defaultFolder_ = await Folder.save({ title: folderTitle });
return defaultFolder_;
}
for (let i = 0; i < stats.length; i++) { for (let i = 0; i < stats.length; i++) {
const stat = stats[i]; const stat = stats[i];
if (stat.isDirectory()) continue; if (stat.isDirectory()) continue;
@ -54,7 +72,22 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
delete item.type_; delete item.type_;
if (itemType === BaseModel.TYPE_NOTE) { if (itemType === BaseModel.TYPE_NOTE) {
if (!folderIdMap[item.parent_id]) folderIdMap[item.parent_id] = destinationFolderId ? destinationFolderId : uuid.create();
// 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 (!folderIdMap[item.parent_id]) {
if (destinationFolderId) {
folderIdMap[item.parent_id] = destinationFolderId;
} else if (!folderExists(stats, item.parent_id)) {
const parentFolder = await defaultFolder();
folderIdMap[item.parent_id] = parentFolder.id;
} else {
folderIdMap[item.parent_id] = uuid.create();
}
}
const noteId = uuid.create(); const noteId = uuid.create();
noteIdMap[item.id] = noteId; noteIdMap[item.id] = noteId;
item.id = noteId; item.id = noteId;