mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
238 lines
6.8 KiB
TypeScript
238 lines
6.8 KiB
TypeScript
import { writeFile, remove, mkdirp } from 'fs-extra';
|
|
import Folder from '../../models/Folder';
|
|
import Note from '../../models/Note';
|
|
import { createTempDir, setupDatabaseAndSynchronizer, supportDir, switchClient } from '../../testing/test-utils';
|
|
import { FolderEntity, NoteEntity, ResourceEntity } from '../database/types';
|
|
import InteropService from './InteropService';
|
|
import { ImportOptions } from './types';
|
|
import { copyFile } from 'fs/promises';
|
|
import Resource from '../../models/Resource';
|
|
|
|
const extractId = (rawContent: string): string => {
|
|
const lines = rawContent.split('\n');
|
|
for (const line of lines) {
|
|
if (line.startsWith('id: ')) return line.substr(4);
|
|
}
|
|
throw new Error(`Could not extract ID from: ${rawContent}`);
|
|
};
|
|
|
|
const makeFilePath = (baseDir: string, itemContent: string): string => {
|
|
return `${baseDir}/${extractId(itemContent)}.md`;
|
|
};
|
|
|
|
const rawFolder1 = `import test
|
|
|
|
id: 15fa3f4abe89429b8836cdc5859fe74b
|
|
created_time: 2022-08-29T14:42:47.684Z
|
|
updated_time: 2022-08-29T14:42:47.684Z
|
|
user_created_time: 2022-08-29T14:42:47.684Z
|
|
user_updated_time: 2022-08-29T14:42:47.684Z
|
|
encryption_cipher_text:
|
|
encryption_applied: 0
|
|
parent_id:
|
|
is_shared: 0
|
|
share_id:
|
|
master_key_id:
|
|
icon:
|
|
type_: 2`;
|
|
|
|
const rawFolder2 = `sub-notebook
|
|
|
|
id: 6c114fa9cc4d421db908a6293418c1b2
|
|
created_time: 2022-08-29T14:42:56.113Z
|
|
updated_time: 2022-08-29T14:43:02.774Z
|
|
user_created_time: 2022-08-29T14:42:56.113Z
|
|
user_updated_time: 2022-08-29T14:43:02.774Z
|
|
encryption_cipher_text:
|
|
encryption_applied: 0
|
|
parent_id: 15fa3f4abe89429b8836cdc5859fe74b
|
|
is_shared: 0
|
|
share_id:
|
|
master_key_id:
|
|
icon:
|
|
type_: 2`;
|
|
|
|
const rawNote1 = `Note 1
|
|
|
|
![photo.jpg](:/b3ab7288b56d4dbf884e73bea1248dd1)
|
|
|
|
id: 7e5e0c7202414cd38e2db12e2e92ac91
|
|
parent_id: 15fa3f4abe89429b8836cdc5859fe74b
|
|
created_time: 2022-08-29T14:43:06.961Z
|
|
updated_time: 2022-08-29T14:43:10.596Z
|
|
is_conflict: 0
|
|
latitude: 53.80075540
|
|
longitude: -1.54907740
|
|
altitude: 0.0000
|
|
author:
|
|
source_url:
|
|
is_todo: 0
|
|
todo_due: 0
|
|
todo_completed: 0
|
|
source: joplindev-desktop
|
|
source_application: net.cozic.joplindev-desktop
|
|
application_data:
|
|
order: 0
|
|
user_created_time: 2022-08-29T14:43:06.961Z
|
|
user_updated_time: 2022-08-29T14:43:10.596Z
|
|
encryption_cipher_text:
|
|
encryption_applied: 0
|
|
markup_language: 1
|
|
is_shared: 0
|
|
share_id:
|
|
conflict_original_id:
|
|
master_key_id:
|
|
type_: 1`;
|
|
|
|
const rawNote2 = `Note 2
|
|
|
|
id: 49faf4793cc048b698a592f9a76567af
|
|
parent_id: 6c114fa9cc4d421db908a6293418c1b2
|
|
created_time: 2022-08-29T14:43:13.117Z
|
|
updated_time: 2022-08-29T14:43:15.023Z
|
|
is_conflict: 0
|
|
latitude: 53.80075540
|
|
longitude: -1.54907740
|
|
altitude: 0.0000
|
|
author:
|
|
source_url:
|
|
is_todo: 0
|
|
todo_due: 0
|
|
todo_completed: 0
|
|
source: joplindev-desktop
|
|
source_application: net.cozic.joplindev-desktop
|
|
application_data:
|
|
order: 0
|
|
user_created_time: 2022-08-29T14:43:13.117Z
|
|
user_updated_time: 2022-08-29T14:43:15.023Z
|
|
encryption_cipher_text:
|
|
encryption_applied: 0
|
|
markup_language: 1
|
|
is_shared: 0
|
|
share_id:
|
|
conflict_original_id:
|
|
master_key_id:
|
|
type_: 1`;
|
|
|
|
const rawResource = `Resource 1
|
|
|
|
id: b3ab7288b56d4dbf884e73bea1248dd1
|
|
mime: image/jpeg
|
|
filename:
|
|
created_time: 2023-12-14T16:54:47.661Z
|
|
updated_time: 2023-12-14T16:54:49.956Z
|
|
user_created_time: 2023-12-14T16:54:47.661Z
|
|
user_updated_time: 2023-12-14T16:54:49.956Z
|
|
file_extension: jpg
|
|
encryption_cipher_text:
|
|
encryption_applied: 0
|
|
encryption_blob_encrypted: 0
|
|
size: 2720
|
|
is_shared: 0
|
|
share_id:
|
|
master_key_id:
|
|
user_data:
|
|
blob_updated_time: 1702572887661
|
|
type_: 4`;
|
|
|
|
let tempDir: string;
|
|
|
|
const createFiles = async () => {
|
|
const resourceDir = `${tempDir}/resources`;
|
|
await mkdirp(resourceDir);
|
|
|
|
await writeFile(makeFilePath(tempDir, rawFolder1), rawFolder1);
|
|
await writeFile(makeFilePath(tempDir, rawFolder2), rawFolder2);
|
|
await writeFile(makeFilePath(tempDir, rawNote1), rawNote1);
|
|
await writeFile(makeFilePath(tempDir, rawNote2), rawNote2);
|
|
await writeFile(makeFilePath(tempDir, rawResource), rawResource);
|
|
await copyFile(`${supportDir}/photo.jpg`, `${resourceDir}/${extractId(rawResource)}.jpg`);
|
|
};
|
|
|
|
describe('InteropService_Importer_Raw', () => {
|
|
|
|
beforeEach(async () => {
|
|
await setupDatabaseAndSynchronizer(1);
|
|
await switchClient(1);
|
|
tempDir = await createTempDir();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await remove(tempDir);
|
|
});
|
|
|
|
it('should import raw files', async () => {
|
|
await createFiles();
|
|
|
|
const importOptions: ImportOptions = {
|
|
path: tempDir,
|
|
format: 'raw',
|
|
destinationFolderId: '',
|
|
};
|
|
|
|
await InteropService.instance().import(importOptions);
|
|
|
|
const folder1: FolderEntity = await Folder.loadByTitle('import test');
|
|
const folder2: FolderEntity = await Folder.loadByTitle('sub-notebook');
|
|
const note1: NoteEntity = await Note.loadByTitle('Note 1');
|
|
const note2: NoteEntity = await Note.loadByTitle('Note 2');
|
|
const resource: ResourceEntity = await Resource.loadByTitle('Resource 1');
|
|
|
|
// Check that all items have been created
|
|
expect(folder1).toBeTruthy();
|
|
expect(folder2).toBeTruthy();
|
|
expect(note1).toBeTruthy();
|
|
expect(note2).toBeTruthy();
|
|
expect(resource).toBeTruthy();
|
|
|
|
// Check that all IDs have been replaced - we don't keep the original
|
|
// IDs when importing data.
|
|
expect(folder1.id).not.toBe(extractId(rawFolder1));
|
|
expect(folder2.id).not.toBe(extractId(rawFolder2));
|
|
expect(note1.id).not.toBe(extractId(rawNote1));
|
|
expect(note2.id).not.toBe(extractId(rawNote2));
|
|
expect(resource.id).not.toBe(extractId(rawResource));
|
|
|
|
// Check that the notes are linked to the correct folder IDs
|
|
expect(folder1.parent_id).toBe('');
|
|
expect(folder2.parent_id).toBe(folder1.id);
|
|
expect(note1.parent_id).toBe(folder1.id);
|
|
expect(note2.parent_id).toBe(folder2.id);
|
|
|
|
// Check that the resource is still linked to the note and with the
|
|
// correct ID.
|
|
expect(note1.body).toBe(`![photo.jpg](:/${resource.id})`);
|
|
});
|
|
|
|
it('should handle duplicate names', async () => {
|
|
await createFiles();
|
|
|
|
const importOptions: ImportOptions = {
|
|
path: tempDir,
|
|
format: 'raw',
|
|
destinationFolderId: '',
|
|
};
|
|
|
|
// Import twice to create duplicate items
|
|
await InteropService.instance().import(importOptions);
|
|
await InteropService.instance().import(importOptions);
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
|
const tree: any = await Folder.allAsTree(null, { includeNotes: true });
|
|
|
|
expect(tree[0].title).toBe('import test');
|
|
expect(tree[0].notes[0].title).toBe('Note 1');
|
|
expect(tree[0].children[0].title).toBe('sub-notebook');
|
|
expect(tree[0].children[0].notes[0].title).toBe('Note 2');
|
|
|
|
// The first notebook should have a (1) because it's at the same level
|
|
// as the other "import test" notebook. Its content however should not
|
|
// have any (x) because they are at different levels.
|
|
expect(tree[1].title).toBe('import test (1)');
|
|
expect(tree[1].notes[0].title).toBe('Note 1');
|
|
expect(tree[1].children[0].title).toBe('sub-notebook');
|
|
expect(tree[1].children[0].notes[0].title).toBe('Note 2');
|
|
});
|
|
|
|
});
|