mirror of
https://github.com/laurent22/joplin.git
synced 2024-11-27 08:21:03 +02:00
Server: Fixed crash when rendering note with links to non-existing resources or notes
This commit is contained in:
parent
61399cec62
commit
07484de91e
@ -79,8 +79,14 @@ export default class Application extends BaseApplication {
|
||||
return `${itemId}.md`;
|
||||
}
|
||||
|
||||
private async itemMetadataFile(parentId: Uuid, itemId: string): Promise<File> {
|
||||
private async itemMetadataFile(parentId: Uuid, itemId: string): Promise<File | null> {
|
||||
const file = await this.models.file().fileByName(parentId, this.itemIdFilename(itemId), { skipPermissionCheck: true });
|
||||
if (!file) {
|
||||
// We don't throw an error because it can happen if the note
|
||||
// contains an invalid link to a resource or note.
|
||||
logger.error(`Could not find item with ID "${itemId}" on parent "${parentId}"`);
|
||||
return null;
|
||||
}
|
||||
return this.models.file().loadWithContent(file.id, { skipPermissionCheck: true });
|
||||
}
|
||||
|
||||
@ -114,6 +120,8 @@ export default class Application extends BaseApplication {
|
||||
|
||||
for (const itemId of itemIds) {
|
||||
const itemFile = await this.itemMetadataFile(noteFileParentId, itemId);
|
||||
if (!itemFile) continue;
|
||||
|
||||
output[itemId] = {
|
||||
item: await this.unserializeItem(itemFile),
|
||||
file: itemFile,
|
||||
@ -162,6 +170,8 @@ export default class Application extends BaseApplication {
|
||||
resources: resourceInfos,
|
||||
|
||||
itemIdToUrl: (itemId: Uuid) => {
|
||||
if (!linkedItemInfos[itemId]) return '#';
|
||||
|
||||
const item = linkedItemInfos[itemId].item;
|
||||
if (!item) throw new Error(`No such item in this note: ${itemId}`);
|
||||
|
||||
|
@ -1,7 +1,39 @@
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import routeHandler from '../../middleware/routeHandler';
|
||||
import { putFileContent, testFilePath, postDirectory } from '../../utils/testing/fileApiUtils';
|
||||
import { postShare } from '../../utils/testing/shareApiUtils';
|
||||
import { beforeAllDb, afterAllTests, parseHtml, beforeEachDb, createUserAndSession, createFile, koaAppContext, checkContextError } from '../../utils/testing/testUtils';
|
||||
import { beforeAllDb, afterAllTests, parseHtml, beforeEachDb, createUserAndSession, createFile, koaAppContext, checkContextError, expectNotThrow } from '../../utils/testing/testUtils';
|
||||
|
||||
function makeNoteSerializedBody(note: NoteEntity): string {
|
||||
return `${'title' in note ? note.title : 'Title'}
|
||||
|
||||
${'body' in note ? note.body : 'Body'}
|
||||
|
||||
id: ${'id' in note ? note.id : 'b39dadd7a63742bebf3125fd2a9286d4'}
|
||||
parent_id: e98f305dde8b47b793f031cf883324ff
|
||||
created_time: 2020-10-15T10:34:16.044Z
|
||||
updated_time: 2021-01-28T23:10:30.054Z
|
||||
is_conflict: 0
|
||||
latitude: 0.00000000
|
||||
longitude: 0.00000000
|
||||
altitude: 0.0000
|
||||
author:
|
||||
source_url:
|
||||
is_todo: 1
|
||||
todo_due: 1602760405000
|
||||
todo_completed: 0
|
||||
source: joplindev-desktop
|
||||
source_application: net.cozic.joplindev-desktop
|
||||
application_data:
|
||||
order: 0
|
||||
user_created_time: 2020-10-15T10:34:16.044Z
|
||||
user_updated_time: 2020-10-19T17:21:03.394Z
|
||||
encryption_cipher_text:
|
||||
encryption_applied: 0
|
||||
markup_language: 1
|
||||
is_shared: 1
|
||||
type_: 1`;
|
||||
}
|
||||
|
||||
const resourceSize = 2720;
|
||||
|
||||
@ -25,97 +57,6 @@ type_: 4`,
|
||||
|
||||
};
|
||||
|
||||
const noteContents: Record<string, string> = {
|
||||
|
||||
simple: `Testing title
|
||||
|
||||
Testing body
|
||||
|
||||
id: b39dadd7a63742bebf3125fd2a9286d4
|
||||
parent_id: e98f305dde8b47b793f031cf883324ff
|
||||
created_time: 2020-10-15T10:34:16.044Z
|
||||
updated_time: 2021-01-28T23:10:30.054Z
|
||||
is_conflict: 0
|
||||
latitude: 0.00000000
|
||||
longitude: 0.00000000
|
||||
altitude: 0.0000
|
||||
author:
|
||||
source_url:
|
||||
is_todo: 1
|
||||
todo_due: 1602760405000
|
||||
todo_completed: 0
|
||||
source: joplindev-desktop
|
||||
source_application: net.cozic.joplindev-desktop
|
||||
application_data:
|
||||
order: 0
|
||||
user_created_time: 2020-10-15T10:34:16.044Z
|
||||
user_updated_time: 2020-10-19T17:21:03.394Z
|
||||
encryption_cipher_text:
|
||||
encryption_applied: 0
|
||||
markup_language: 1
|
||||
is_shared: 1
|
||||
type_: 1`,
|
||||
|
||||
katex: `Katex Test
|
||||
|
||||
$\\sqrt{3x-1}+(1+x)^2$
|
||||
|
||||
id: b39dadd7a63742bebf3125fd2a9286d4
|
||||
parent_id: e98f305dde8b47b793f031cf883324ff
|
||||
created_time: 2020-10-15T10:34:16.044Z
|
||||
updated_time: 2021-01-28T23:10:30.054Z
|
||||
is_conflict: 0
|
||||
latitude: 0.00000000
|
||||
longitude: 0.00000000
|
||||
altitude: 0.0000
|
||||
author:
|
||||
source_url:
|
||||
is_todo: 1
|
||||
todo_due: 1602760405000
|
||||
todo_completed: 0
|
||||
source: joplindev-desktop
|
||||
source_application: net.cozic.joplindev-desktop
|
||||
application_data:
|
||||
order: 0
|
||||
user_created_time: 2020-10-15T10:34:16.044Z
|
||||
user_updated_time: 2020-10-19T17:21:03.394Z
|
||||
encryption_cipher_text:
|
||||
encryption_applied: 0
|
||||
markup_language: 1
|
||||
is_shared: 1
|
||||
type_: 1`,
|
||||
|
||||
image: `Image Test
|
||||
|
||||
![my image](:/96765a68655f4446b3dbad7d41b6566e)
|
||||
|
||||
id: b39dadd7a63742bebf3125fd2a9286d4
|
||||
parent_id: e98f305dde8b47b793f031cf883324ff
|
||||
created_time: 2020-10-15T10:34:16.044Z
|
||||
updated_time: 2021-01-28T23:10:30.054Z
|
||||
is_conflict: 0
|
||||
latitude: 0.00000000
|
||||
longitude: 0.00000000
|
||||
altitude: 0.0000
|
||||
author:
|
||||
source_url:
|
||||
is_todo: 1
|
||||
todo_due: 1602760405000
|
||||
todo_completed: 0
|
||||
source: joplindev-desktop
|
||||
source_application: net.cozic.joplindev-desktop
|
||||
application_data:
|
||||
order: 0
|
||||
user_created_time: 2020-10-15T10:34:16.044Z
|
||||
user_updated_time: 2020-10-19T17:21:03.394Z
|
||||
encryption_cipher_text:
|
||||
encryption_applied: 0
|
||||
markup_language: 1
|
||||
is_shared: 1
|
||||
type_: 1`,
|
||||
|
||||
};
|
||||
|
||||
async function getShareContent(shareId: string, query: any = {}): Promise<string | Buffer> {
|
||||
const context = await koaAppContext({
|
||||
request: {
|
||||
@ -146,7 +87,10 @@ describe('shares.joplin', function() {
|
||||
test('should display a simple note', async function() {
|
||||
const { user, session } = await createUserAndSession();
|
||||
|
||||
await createFile(user.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:', noteContents.simple);
|
||||
await createFile(user.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:', makeNoteSerializedBody({
|
||||
title: 'Testing title',
|
||||
body: 'Testing body',
|
||||
}));
|
||||
|
||||
const share = await postShare(session.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:');
|
||||
|
||||
@ -161,7 +105,9 @@ describe('shares.joplin', function() {
|
||||
test('should load plugins', async function() {
|
||||
const { user, session } = await createUserAndSession();
|
||||
|
||||
await createFile(user.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:', noteContents.katex);
|
||||
await createFile(user.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:', makeNoteSerializedBody({
|
||||
body: '$\\sqrt{3x-1}+(1+x)^2$',
|
||||
}));
|
||||
|
||||
const share = await postShare(session.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:');
|
||||
|
||||
@ -173,7 +119,9 @@ describe('shares.joplin', function() {
|
||||
test('should render attached images', async function() {
|
||||
const { user, session } = await createUserAndSession();
|
||||
|
||||
await createFile(user.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:', noteContents.image);
|
||||
await createFile(user.id, 'root:/b39dadd7a63742bebf3125fd2a9286d4.md:', makeNoteSerializedBody({
|
||||
body: '![my image](:/96765a68655f4446b3dbad7d41b6566e)',
|
||||
}));
|
||||
await postDirectory(session.id, 'root', '.resource');
|
||||
await putFileContent(session.id, 'root:/.resource/96765a68655f4446b3dbad7d41b6566e:', testFilePath());
|
||||
await createFile(user.id, 'root:/96765a68655f4446b3dbad7d41b6566e.md:', resourceContents.image);
|
||||
@ -200,4 +148,26 @@ describe('shares.joplin', function() {
|
||||
expect(resourceContent.byteLength).toBe(resourceSize);
|
||||
});
|
||||
|
||||
test('should not throw an error if the note contains links to non-existing items', async function() {
|
||||
const { user, session } = await createUserAndSession();
|
||||
|
||||
{
|
||||
const noteId = 'b39dadd7a63742bebf3125fd2a9286d4';
|
||||
await createFile(user.id, `root:/${noteId}.md:`, makeNoteSerializedBody({
|
||||
body: '![missing](:/531a2a839a2c493a88c45e39c6cb9ed4)',
|
||||
}));
|
||||
const share = await postShare(session.id, `root:/${noteId}.md:`);
|
||||
await expectNotThrow(async () => getShareContent(share.id));
|
||||
}
|
||||
|
||||
{
|
||||
const noteId = 'b39dadd7a63742bebf3125fd2a9286d5';
|
||||
await createFile(user.id, `root:/${noteId}.md:`, makeNoteSerializedBody({
|
||||
body: '[missing too](:/531a2a839a2c493a88c45e39c6cb9ed4)',
|
||||
}));
|
||||
const share = await postShare(session.id, `root:/${noteId}.md:`);
|
||||
await expectNotThrow(async () => getShareContent(share.id));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user