mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-11-04 15:11:31 +08:00 
			
		
		
		
	export & import work correctly with clones
This commit is contained in:
		
							parent
							
								
									b277a250e5
								
							
						
					
					
						commit
						1f96a6beab
					
				@ -13,50 +13,31 @@ async function exportNote(req, res) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const pack = tar.pack();
 | 
					    const pack = tar.pack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const name = await exportNoteInner(branchId, '', pack);
 | 
					    const exportedNoteIds = [];
 | 
				
			||||||
 | 
					    const name = await exportNoteInner(branchId, '');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pack.finalize();
 | 
					    async function exportNoteInner(branchId, directory) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    res.setHeader('Content-Disposition', 'file; filename="' + name + '.tar"');
 | 
					 | 
				
			||||||
    res.setHeader('Content-Type', 'application/tar');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pack.pipe(res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function exportNoteInner(branchId, directory, pack) {
 | 
					 | 
				
			||||||
        const branch = await repository.getBranch(branchId);
 | 
					        const branch = await repository.getBranch(branchId);
 | 
				
			||||||
        const note = await branch.getNote();
 | 
					        const note = await branch.getNote();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (note.isProtected) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const metadata = await getMetadata(note);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (metadata.labels.find(label => label.name === 'excludeFromExport')) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const metadataJson = JSON.stringify(metadata, null, '\t');
 | 
					 | 
				
			||||||
        const childFileName = directory + sanitize(note.title);
 | 
					        const childFileName = directory + sanitize(note.title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pack.entry({ name: childFileName + ".meta", size: metadataJson.length }, metadataJson);
 | 
					        if (exportedNoteIds.includes(note.noteId)) {
 | 
				
			||||||
 | 
					            saveMetadataFile(childFileName, {
 | 
				
			||||||
 | 
					                version: 1,
 | 
				
			||||||
 | 
					                clone: true,
 | 
				
			||||||
 | 
					                noteId: note.noteId,
 | 
				
			||||||
 | 
					                prefix: branch.prefix
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const content = note.type === 'text' ? html.prettyPrint(note.content, {indent_size: 2}) : note.content;
 | 
					            return;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    pack.entry({ name: childFileName + ".dat", size: content.length }, content);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (const child of await note.getChildBranches()) {
 | 
					 | 
				
			||||||
        await exportNoteInner(child.branchId, childFileName + "/", pack);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return childFileName;
 | 
					        const metadata = {
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function getMetadata(note) {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
            version: 1,
 | 
					            version: 1,
 | 
				
			||||||
 | 
					            clone: false,
 | 
				
			||||||
 | 
					            noteId: note.noteId,
 | 
				
			||||||
            title: note.title,
 | 
					            title: note.title,
 | 
				
			||||||
 | 
					            prefix: branch.prefix,
 | 
				
			||||||
            type: note.type,
 | 
					            type: note.type,
 | 
				
			||||||
            mime: note.mime,
 | 
					            mime: note.mime,
 | 
				
			||||||
            labels: (await note.getLabels()).map(label => {
 | 
					            labels: (await note.getLabels()).map(label => {
 | 
				
			||||||
@ -66,6 +47,41 @@ async function getMetadata(note) {
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (metadata.labels.find(label => label.name === 'excludeFromExport')) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        saveMetadataFile(childFileName, metadata);
 | 
				
			||||||
 | 
					        saveDataFile(childFileName, note);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        exportedNoteIds.push(note.noteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const child of await note.getChildBranches()) {
 | 
				
			||||||
 | 
					            await exportNoteInner(child.branchId, childFileName + "/");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return childFileName;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function saveDataFile(childFileName, note) {
 | 
				
			||||||
 | 
					        const content = note.type === 'text' ? html.prettyPrint(note.content, {indent_size: 2}) : note.content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pack.entry({name: childFileName + ".dat", size: content.length}, content);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function saveMetadataFile(childFileName, metadata) {
 | 
				
			||||||
 | 
					        const metadataJson = JSON.stringify(metadata, null, '\t');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pack.entry({name: childFileName + ".meta", size: metadataJson.length}, metadataJson);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pack.finalize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.setHeader('Content-Disposition', 'file; filename="' + name + '.tar"');
 | 
				
			||||||
 | 
					    res.setHeader('Content-Type', 'application/tar');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pack.pipe(res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
const repository = require('../../services/repository');
 | 
					const repository = require('../../services/repository');
 | 
				
			||||||
const labelService = require('../../services/labels');
 | 
					const labelService = require('../../services/labels');
 | 
				
			||||||
const noteService = require('../../services/notes');
 | 
					const noteService = require('../../services/notes');
 | 
				
			||||||
 | 
					const Branch = require('../../entities/branch');
 | 
				
			||||||
const tar = require('tar-stream');
 | 
					const tar = require('tar-stream');
 | 
				
			||||||
const stream = require('stream');
 | 
					const stream = require('stream');
 | 
				
			||||||
const path = require('path');
 | 
					const path = require('path');
 | 
				
			||||||
@ -31,7 +32,7 @@ async function parseImportFile(file) {
 | 
				
			|||||||
    const extract = tar.extract();
 | 
					    const extract = tar.extract();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    extract.on('entry', function(header, stream, next) {
 | 
					    extract.on('entry', function(header, stream, next) {
 | 
				
			||||||
        let {name, key} = getFileName(header.name);
 | 
					        const {name, key} = getFileName(header.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let file = fileMap[name];
 | 
					        let file = fileMap[name];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,30 +98,46 @@ async function importTar(req) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const files = await parseImportFile(file);
 | 
					    const files = await parseImportFile(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await importNotes(files, parentNoteId);
 | 
					    // maps from original noteId (in tar file) to newly generated noteId
 | 
				
			||||||
 | 
					    const noteIdMap = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await importNotes(files, parentNoteId, noteIdMap);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function importNotes(files, parentNoteId) {
 | 
					async function importNotes(files, parentNoteId, noteIdMap) {
 | 
				
			||||||
    for (const file of files) {
 | 
					    for (const file of files) {
 | 
				
			||||||
        if (file.meta.version !== 1) {
 | 
					        if (file.meta.version !== 1) {
 | 
				
			||||||
            throw new Error("Can't read meta data version " + file.meta.version);
 | 
					            throw new Error("Can't read meta data version " + file.meta.version);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (file.meta.clone) {
 | 
				
			||||||
 | 
					            await new Branch({
 | 
				
			||||||
 | 
					                parentNoteId: parentNoteId,
 | 
				
			||||||
 | 
					                noteId: noteIdMap[file.meta.noteId],
 | 
				
			||||||
 | 
					                prefix: file.meta.prefix
 | 
				
			||||||
 | 
					            }).save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (file.meta.type !== 'file') {
 | 
					        if (file.meta.type !== 'file') {
 | 
				
			||||||
            file.data = file.data.toString("UTF-8");
 | 
					            file.data = file.data.toString("UTF-8");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const {note} = await noteService.createNote(parentNoteId, file.meta.title, file.data, {
 | 
					        const {note} = await noteService.createNote(parentNoteId, file.meta.title, file.data, {
 | 
				
			||||||
            type: file.meta.type,
 | 
					            type: file.meta.type,
 | 
				
			||||||
            mime: file.meta.mime
 | 
					            mime: file.meta.mime,
 | 
				
			||||||
 | 
					            prefix: file.meta.prefix
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        noteIdMap[file.meta.noteId] = note.noteId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const label of file.meta.labels) {
 | 
					        for (const label of file.meta.labels) {
 | 
				
			||||||
            await labelService.createLabel(note.noteId, label.name, label.value);
 | 
					            await labelService.createLabel(note.noteId, label.name, label.value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (file.children.length > 0) {
 | 
					        if (file.children.length > 0) {
 | 
				
			||||||
            await importNotes(file.children, note.noteId);
 | 
					            await importNotes(file.children, note.noteId, noteIdMap);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -56,6 +56,7 @@ async function createNewNote(parentNoteId, noteData) {
 | 
				
			|||||||
        noteId: note.noteId,
 | 
					        noteId: note.noteId,
 | 
				
			||||||
        parentNoteId: parentNoteId,
 | 
					        parentNoteId: parentNoteId,
 | 
				
			||||||
        notePosition: newNotePos,
 | 
					        notePosition: newNotePos,
 | 
				
			||||||
 | 
					        prefix: noteData.prefix,
 | 
				
			||||||
        isExpanded: 0
 | 
					        isExpanded: 0
 | 
				
			||||||
    }).save();
 | 
					    }).save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user