From 7bdbea81f1bb8ba05605aa8731c44d9fb0ed133f Mon Sep 17 00:00:00 2001 From: azivner Date: Mon, 5 Nov 2018 12:52:50 +0100 Subject: [PATCH] enex import recognizes images, media references are converted to links --- src/routes/api/image.js | 6 ++--- src/services/enex.js | 45 ++++++++++++++++++++++++++++------ src/services/image.js | 14 +++++++---- src/services/utils.js | 11 +++++++++ src/test/enex/Export-test.enex | 10 ++++++-- 5 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/routes/api/image.js b/src/routes/api/image.js index 1e39a5bf5..0c14b2474 100644 --- a/src/routes/api/image.js +++ b/src/routes/api/image.js @@ -1,6 +1,6 @@ "use strict"; -const image = require('../../services/image'); +const imageService = require('../../services/image'); const repository = require('../../services/repository'); const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR; const fs = require('fs'); @@ -35,11 +35,11 @@ async function uploadImage(req) { return [400, "Unknown image type: " + file.mimetype]; } - const {fileName, imageId} = await image.saveImage(file, noteId); + const {url} = await imageService.saveImage(file.buffer, file.originalname, noteId); return { uploaded: true, - url: `/api/images/${imageId}/${fileName}` + url }; } diff --git a/src/services/enex.js b/src/services/enex.js index 3b706b097..6ac21f104 100644 --- a/src/services/enex.js +++ b/src/services/enex.js @@ -4,6 +4,7 @@ const xml2js = require('xml2js'); 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) { @@ -205,20 +206,50 @@ async function importEnex(file, parentNote) { // following is workaround for this issue: https://github.com/Leonidas-from-XIV/node-xml2js/issues/484 content = extractContent(xmlObject['en-note']); - const resp = await noteService.createNote(rootNote.noteId, title, content, { + const noteEntity = (await noteService.createNote(rootNote.noteId, title, content, { attributes, dateCreated, type: 'text', mime: 'text/html' - }); + })).note; for (const resource of resources) { - await noteService.createNote(resp.note.noteId, resource.title, resource.content, { - attributes: resource.attributes, - type: 'file', - mime: resource.mime - }); + const hash = utils.md5(resource.content); + + const mediaRegex = new RegExp(`]*>`, 'g'); + + if (resource.mime.startsWith("image/")) { + const originalName = "image." + resource.mime.substr(6); + + const { url } = await imageService.saveImage(resource.content, originalName, noteEntity.noteId); + + const imageLink = ``; + + noteEntity.content = noteEntity.content.replace(mediaRegex, imageLink); + + if (!note.content.includes(imageLink)) { + // if there wasn't any match for the reference, we'll add the image anyway + // otherwise image would be removed since no note would include it + note.content += imageLink; + } + } + else { + const resourceNote = (await noteService.createNote(noteEntity.noteId, resource.title, resource.content, { + attributes: resource.attributes, + type: 'file', + mime: resource.mime + })).note; + + const resourceLink = `${utils.escapeHtml(resource.title)}`; + + noteEntity.content = noteEntity.content.replace(mediaRegex, resourceLink); + } } + + // save updated content with links to files/images + await noteEntity.save(); + + console.log(noteEntity.content); } saxStream.on("closetag", async tag => { diff --git a/src/services/image.js b/src/services/image.js index 7edd4c130..696319363 100644 --- a/src/services/image.js +++ b/src/services/image.js @@ -11,14 +11,14 @@ const jimp = require('jimp'); const imageType = require('image-type'); const sanitizeFilename = require('sanitize-filename'); -async function saveImage(file, noteId) { - const resizedImage = await resize(file.buffer); +async function saveImage(buffer, originalName, noteId) { + const resizedImage = await resize(buffer); const optimizedImage = await optimize(resizedImage); const imageFormat = imageType(optimizedImage); - const fileNameWithouExtension = file.originalname.replace(/\.[^/.]+$/, ""); - const fileName = sanitizeFilename(fileNameWithouExtension + "." + imageFormat.ext); + const fileNameWithoutExtension = originalName.replace(/\.[^/.]+$/, ""); + const fileName = sanitizeFilename(fileNameWithoutExtension + "." + imageFormat.ext); const image = await new Image({ format: imageFormat.ext, @@ -32,7 +32,11 @@ async function saveImage(file, noteId) { imageId: image.imageId }).save(); - return {fileName, imageId: image.imageId}; + return { + fileName, + imageId: image.imageId, + url: `/api/images/${image.imageId}/${fileName}` + }; } const MAX_SIZE = 1000; diff --git a/src/services/utils.js b/src/services/utils.js index 140a5d91f..9e79bb14e 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -3,6 +3,7 @@ const crypto = require('crypto'); const randtoken = require('rand-token').generator({source: 'crypto'}); const unescape = require('unescape'); +const escape = require('escape-html'); function newEntityId() { return randomString(12); @@ -16,6 +17,10 @@ function randomSecureToken(bytes = 32) { return crypto.randomBytes(bytes).toString('base64'); } +function md5(content) { + return crypto.createHash('md5').update(content).digest('hex'); +} + function toBase64(plainText) { return Buffer.from(plainText).toString('base64'); } @@ -59,6 +64,10 @@ async function stopWatch(what, func) { return ret; } +function escapeHtml(str) { + return escape(str); +} + function unescapeHtml(str) { return unescape(str); } @@ -108,6 +117,7 @@ function union(a, b) { module.exports = { randomSecureToken, randomString, + md5, newEntityId, toBase64, fromBase64, @@ -117,6 +127,7 @@ module.exports = { isEmptyOrWhitespace, sanitizeSql, stopWatch, + escapeHtml, unescapeHtml, toObject, stripTags, diff --git a/src/test/enex/Export-test.enex b/src/test/enex/Export-test.enex index 6aa6e69b8..0d2a4027e 100644 --- a/src/test/enex/Export-test.enex +++ b/src/test/enex/Export-test.enex @@ -1,6 +1,6 @@ - + Formatted text @@ -5485,4 +5485,10 @@ OTg3NjMyOSwyNzkxMTA0MTYwLDEwNTc1NjM5NDksMzI1NTM2MzIzMSwzMDc1MzY3MjE4LDM0NjM5 NjMyMjcsMTQ2OTA0Njc1NSw5ODU4ODc0NjJdLEU9WzEzMzI4OTk5NDQsMTcwMDg4NDAzNCwxNzAx MzQzMDg0LDE2ODQzNzAwMDMsMTY2ODQ0NjUzMiwKMTg2OTk2Mzg5Ml07ay5lbmNvZGVCYXNlNjQ9 eDtrLmRlY29kZUJhc2U2ND1CO3JldHVybiBrfSk7Cg== -application/octet-streamfile://Z:\home\adam\Downloads\bcrypt.min.jsbcrypt.min.jstrue +application/octet-streamfile://Z:\home\adam\Downloads\bcrypt.min.jsbcrypt.min.jstrueInternal link to another note + + +
Link to another note: Formatted text
]]>
20181105T094707Z20181105T095117ZAdam Zivnerdesktop.winevernote.win32
Table + + +

header1
header2
header3
abc
def
ghi
123
456
789


]]>
20181105T094826Z20181105T094949ZAdam Zivnerdesktop.winevernote.win32