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:
parent
5ba98b4200
commit
a078947d6d
@ -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');
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user