1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-03-20 20:55:18 +02:00

Desktop, Cli: Improved error handling when importing ENEX files

This commit is contained in:
Laurent Cozic 2020-12-23 17:25:26 +00:00
parent 18c5404cbc
commit 5826a8d373
6 changed files with 53 additions and 10 deletions

@ -55,7 +55,7 @@ class Command extends BaseCommand {
};
importOptions.onError = error => {
const s = error.trace ? error.trace : error.toString();
const s = error.stack ? error.stack : error.toString();
this.stdout(s);
};

@ -131,4 +131,19 @@ describe('EnexToMd', function() {
expect(all[0].mime).toBe('application/zip');
});
it('should keep importing notes when one of them is corrupted', async () => {
const filePath = `${enexSampleBaseDir}/ImportTestCorrupt.enex`;
const errors: any[] = [];
await importEnex('', filePath, {
onError: (error: any) => errors.push(error),
});
const notes = await Note.all();
expect(notes.length).toBe(2);
// Check that an error was recorded and that it includes the title
// of the note, so that it can be found back by the user
expect(errors.length).toBe(1);
expect(errors[0].message.includes('Note 2')).toBe(true);
});
});

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
<en-export export-date="20201223T164244Z" application="Evernote/Windows" version="6.x">
<note><title>Note 1</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div>Plain note</div></en-note>]]></content><created>20201223T163948Z</created><updated>20201223T163953Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>Note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr<td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div><br/></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bl</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td></tr></tbody></table><div><br/></div></div><div><br/></div></en-note>]]></content><created>20201223T164010Z</created><updated>20201223T164023Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>plain note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div><br/></div></en-note>]]></content><created>20201223T164236Z</created><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note></en-export>

@ -137,6 +137,8 @@ function useMenu(props: Props) {
void CommandService.instance().execute('showModalMessage', modalMessage);
const errors: any[] = [];
const importOptions = {
path,
format: module.format,
@ -148,7 +150,10 @@ function useMenu(props: Props) {
void CommandService.instance().execute('showModalMessage', `${modalMessage}\n\n${statusStrings.join('\n')}`);
},
onError: console.warn,
onError: (error: any) => {
errors.push(error);
console.warn(error);
},
destinationFolderId: !module.isNoteArchive && moduleSource === 'file' ? props.selectedFolderId : null,
};
@ -160,6 +165,11 @@ function useMenu(props: Props) {
bridge().showErrorMessageBox(error.message);
}
if (errors.length) {
bridge().showErrorMessageBox('There was some errors importing the notes. Please check the console for more details.');
props.dispatch({ type: 'NOTE_DEVTOOLS_SET', value: true });
}
void CommandService.instance().execute('hideModalMessage');
}, [props.selectedFolderId]);

@ -6,6 +6,7 @@ const Tag = require('./models/Tag.js');
const Resource = require('./models/Resource.js');
const Setting = require('./models/Setting').default;
const { MarkupToHtml } = require('@joplin/renderer');
const { wrapError } = require('./errorUtils');
const { enexXmlToMd } = require('./import-enex-md-gen.js');
const { enexXmlToHtml } = require('./import-enex-html-gen.js');
const time = require('./time').default;
@ -324,13 +325,13 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
async function processNotes() {
if (processingNotes) return false;
try {
processingNotes = true;
stream.pause();
processingNotes = true;
stream.pause();
while (notes.length) {
const note = notes.shift();
while (notes.length) {
const note = notes.shift();
try {
for (let i = 0; i < note.resources.length; i++) {
let resource = note.resources[i];
@ -384,9 +385,10 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
progressState.resourcesCreated += result.resourcesCreated;
progressState.notesTagged += result.notesTagged;
importOptions.onProgress(progressState);
} catch (error) {
const newError = wrapError(`Error on note "${note.title}"`, error);
importOptions.onError(newError);
}
} catch (error) {
console.error(error);
}
stream.resume();

@ -225,7 +225,10 @@ export default class CommandService extends BaseService {
public async execute(commandName: string, ...args: any[]): Promise<any | void> {
const command = this.commandByName(commandName);
this.logger().info('CommandService::execute:', commandName, args);
// Some commands such as "showModalMessage" can be executed many
// times per seconds, so we should only display this message in
// debug mode.
this.logger().debug('CommandService::execute:', commandName, args);
if (!command.runtime) throw new Error(`Cannot execute a command without a runtime: ${commandName}`);
return command.runtime.execute(this.createContext(), ...args);
}