mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
added links to the import/export + fixing internal links inside note content
This commit is contained in:
parent
46c7901e1f
commit
e0f9a7fc6a
@ -115,8 +115,10 @@ async function exportToTar(branch, res) {
|
||||
noteId: note.noteId,
|
||||
title: note.title,
|
||||
prefix: branch.prefix,
|
||||
isExpanded: branch.isExpanded,
|
||||
type: note.type,
|
||||
mime: note.mime,
|
||||
// we don't export dateCreated and dateModified of any entity since that would be a bit misleading
|
||||
attributes: (await note.getOwnedAttributes()).map(attribute => {
|
||||
return {
|
||||
type: attribute.type,
|
||||
@ -125,6 +127,12 @@ async function exportToTar(branch, res) {
|
||||
isInheritable: attribute.isInheritable,
|
||||
position: attribute.position
|
||||
};
|
||||
}),
|
||||
links: (await note.getLinks()).map(link => {
|
||||
return {
|
||||
type: link.type,
|
||||
targetNoteId: link.targetNoteId
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
const Attribute = require('../../entities/attribute');
|
||||
const Link = require('../../entities/link');
|
||||
const repository = require('../../services/repository');
|
||||
const log = require('../../services/log');
|
||||
const enex = require('../../services/enex');
|
||||
const attributeService = require('../../services/attributes');
|
||||
const utils = require('../../services/utils');
|
||||
const enex = require('../../services/import/enex');
|
||||
const noteService = require('../../services/notes');
|
||||
const Branch = require('../../entities/branch');
|
||||
const tar = require('tar-stream');
|
||||
@ -93,33 +95,64 @@ async function importOpml(file, parentNote) {
|
||||
return returnNote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complication of this export is the need to balance two needs:
|
||||
* -
|
||||
*/
|
||||
async function importTar(file, parentNote) {
|
||||
const files = await parseImportFile(file);
|
||||
|
||||
const ctx = {
|
||||
// maps from original noteId (in tar file) to newly generated noteId
|
||||
noteIdMap: {},
|
||||
// new noteIds of notes which were actually created (not just referenced)
|
||||
createdNoteIds: [],
|
||||
attributes: [],
|
||||
links: [],
|
||||
reader: new commonmark.Parser(),
|
||||
writer: new commonmark.HtmlRenderer()
|
||||
};
|
||||
|
||||
ctx.getNewNoteId = function(origNoteId) {
|
||||
// in case the original noteId is empty. This probably shouldn't happen, but still good to have this precaution
|
||||
if (!origNoteId.trim()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!ctx.noteIdMap[origNoteId]) {
|
||||
ctx.noteIdMap[origNoteId] = utils.newEntityId();
|
||||
}
|
||||
|
||||
return ctx.noteIdMap[origNoteId];
|
||||
};
|
||||
|
||||
const note = await importNotes(ctx, files, parentNote.noteId);
|
||||
|
||||
// we save attributes after importing notes because we need to have all the relation
|
||||
// targets already existing
|
||||
// we save attributes and links after importing notes because we need to check that target noteIds
|
||||
// have been really created (relation/links with targets outside of the export are not created)
|
||||
|
||||
for (const attr of ctx.attributes) {
|
||||
if (attr.type === 'relation') {
|
||||
// map to local noteId
|
||||
attr.value = ctx.noteIdMap[attr.value];
|
||||
attr.value = ctx.getNewNoteId(attr.value);
|
||||
|
||||
if (!attr.value) {
|
||||
// relation is targeting note not present in the import
|
||||
if (!ctx.createdNoteIds.includes(attr.value)) {
|
||||
// relation targets note outside of the export
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await attributeService.createAttribute(attr);
|
||||
await new Attribute(attr).save();
|
||||
}
|
||||
|
||||
for (const link of ctx.links) {
|
||||
link.targetNoteId = ctx.getNewNoteId(link.targetNoteId);
|
||||
|
||||
if (!ctx.createdNoteIds.includes(link.targetNoteId)) {
|
||||
// link targets note outside of the export
|
||||
continue;
|
||||
}
|
||||
|
||||
await new Link(link).save();
|
||||
}
|
||||
|
||||
return note;
|
||||
@ -252,26 +285,35 @@ async function importNotes(ctx, files, parentNoteId) {
|
||||
if (file.meta.clone) {
|
||||
await new Branch({
|
||||
parentNoteId: parentNoteId,
|
||||
noteId: ctx.noteIdMap[file.meta.noteId],
|
||||
prefix: file.meta.prefix
|
||||
noteId: ctx.getNewNoteId(file.meta.noteId),
|
||||
prefix: file.meta.prefix,
|
||||
isExpanded: !!file.meta.isExpanded
|
||||
}).save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.meta.type !== 'file') {
|
||||
if (file.meta.type !== 'file' && file.meta.type !== 'image') {
|
||||
file.data = file.data.toString("UTF-8");
|
||||
|
||||
// this will replace all internal links (<a> and <img>) inside the body
|
||||
// links pointing outside the export will be broken and changed (ctx.getNewNoteId() will still assign new noteId)
|
||||
for (const link of file.meta.links || []) {
|
||||
// no need to escape the regexp find string since it's a noteId which doesn't contain any special characters
|
||||
file.data = file.data.replace(new RegExp(link.targetNoteId, "g"), ctx.getNewNoteId(link.targetNoteId));
|
||||
}
|
||||
}
|
||||
|
||||
note = (await noteService.createNote(parentNoteId, file.meta.title, file.data, {
|
||||
noteId: ctx.getNewNoteId(file.meta.noteId),
|
||||
type: file.meta.type,
|
||||
mime: file.meta.mime,
|
||||
prefix: file.meta.prefix
|
||||
})).note;
|
||||
|
||||
ctx.noteIdMap[file.meta.noteId] = note.noteId;
|
||||
ctx.createdNoteIds.push(note.noteId);
|
||||
|
||||
for (const attribute of file.meta.attributes) {
|
||||
for (const attribute of file.meta.attributes || []) {
|
||||
ctx.attributes.push({
|
||||
noteId: note.noteId,
|
||||
type: attribute.type,
|
||||
@ -281,6 +323,14 @@ async function importNotes(ctx, files, parentNoteId) {
|
||||
position: attribute.position
|
||||
});
|
||||
}
|
||||
|
||||
for (const link of file.meta.links || []) {
|
||||
ctx.links.push({
|
||||
noteId: note.noteId,
|
||||
type: link.type,
|
||||
targetNoteId: link.targetNoteId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// first created note will be activated after import
|
||||
|
@ -1,10 +1,10 @@
|
||||
const sax = require("sax");
|
||||
const stream = require('stream');
|
||||
const xml2js = require('xml2js');
|
||||
const log = require("./log");
|
||||
const utils = require("./utils");
|
||||
const noteService = require("./notes");
|
||||
const imageService = require("./image");
|
||||
const log = require("../log");
|
||||
const utils = require("../utils");
|
||||
const noteService = require("../notes");
|
||||
const imageService = require("../image");
|
||||
|
||||
// date format is e.g. 20181121T193703Z
|
||||
function parseDate(text) {
|
@ -69,6 +69,7 @@ async function createNewNote(parentNoteId, noteData) {
|
||||
noteData.mime = noteData.mime || parentNote.mime;
|
||||
|
||||
const note = await new Note({
|
||||
noteId: noteData.noteId, // optionally can force specific noteId
|
||||
title: noteData.title,
|
||||
content: noteData.content,
|
||||
isProtected: noteData.isProtected,
|
||||
@ -116,6 +117,7 @@ async function createNote(parentNoteId, title, content = "", extraOptions = {})
|
||||
title: title,
|
||||
content: extraOptions.json ? JSON.stringify(content, null, '\t') : content,
|
||||
target: 'into',
|
||||
noteId: extraOptions.noteId,
|
||||
isProtected: !!extraOptions.isProtected,
|
||||
type: extraOptions.type,
|
||||
mime: extraOptions.mime,
|
||||
|
Loading…
x
Reference in New Issue
Block a user