From d2163dacf9de181e5696dbaec55b5ea545843d69 Mon Sep 17 00:00:00 2001 From: ehhc Date: Wed, 18 Apr 2018 20:09:12 +0200 Subject: [PATCH] Fixes #1825 Refactoring of the attachment/image management --- browser/components/CodeEditor.js | 46 +---- browser/components/MarkdownEditor.js | 39 ++-- browser/components/MarkdownPreview.js | 16 +- browser/components/MarkdownSplitEditor.js | 3 +- browser/lib/markdown.js | 6 +- browser/main/Detail/MarkdownNoteDetail.js | 2 + .../main/lib/dataApi/attachmentManagement.js | 164 +++++++++++++++++ browser/main/lib/dataApi/copyImage.js | 2 + browser/main/lib/dataApi/exportNote.js | 3 +- browser/main/lib/dataApi/moveNote.js | 1 + package.json | 1 + tests/dataApi/attachmentManagement.test.js | 168 ++++++++++++++++++ yarn.lock | 6 + 13 files changed, 383 insertions(+), 74 deletions(-) create mode 100644 browser/main/lib/dataApi/attachmentManagement.js create mode 100644 tests/dataApi/attachmentManagement.test.js diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 872e9ad73..dfe072ef2 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -3,12 +3,10 @@ import React from 'react' import _ from 'lodash' import CodeMirror from 'codemirror' import 'codemirror-mode-elixir' -import path from 'path' -import copyImage from 'browser/main/lib/dataApi/copyImage' -import { findStorage } from 'browser/lib/findStorage' -import fs from 'fs' +import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement' import eventEmitter from 'browser/main/lib/eventEmitter' import iconv from 'iconv-lite' + const { ipcRenderer } = require('electron') CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js' @@ -275,23 +273,13 @@ export default class CodeEditor extends React.Component { this.editor.setCursor(cursor) } - handleDropImage (e) { - e.preventDefault() - const ValidImageTypes = ['image/gif', 'image/jpeg', 'image/png'] - - const file = e.dataTransfer.files[0] - const filePath = file.path - const filename = path.basename(filePath) - const fileType = file['type'] - - copyImage(filePath, this.props.storageKey).then((imagePath) => { - var showPreview = ValidImageTypes.indexOf(fileType) > 0 - const imageMd = `${showPreview ? '!' : ''}[${filename}](${path.join('/:storage', imagePath)})` - this.insertImageMd(imageMd) - }) + handleDropImage (dropEvent) { + dropEvent.preventDefault() + const {storageKey, noteKey} = this.props + attachmentManagement.handleAttachmentDrop(this, storageKey, noteKey, dropEvent) } - insertImageMd (imageMd) { + insertAttachmentMd (imageMd) { this.editor.replaceSelection(imageMd) } @@ -317,24 +305,8 @@ export default class CodeEditor extends React.Component { return prevChar === '](' && nextChar === ')' } if (dataTransferItem.type.match('image')) { - const blob = dataTransferItem.getAsFile() - const reader = new FileReader() - let base64data - - reader.readAsDataURL(blob) - reader.onloadend = () => { - base64data = reader.result.replace(/^data:image\/png;base64,/, '') - base64data += base64data.replace('+', ' ') - const binaryData = new Buffer(base64data, 'base64').toString('binary') - const imageName = Math.random().toString(36).slice(-16) - const storagePath = findStorage(this.props.storageKey).path - const imageDir = path.join(storagePath, 'images') - if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir) - const imagePath = path.join(imageDir, `${imageName}.png`) - fs.writeFile(imagePath, binaryData, 'binary') - const imageMd = `![${imageName}](${path.join('/:storage', `${imageName}.png`)})` - this.insertImageMd(imageMd) - } + const {storageKey, noteKey} = this.props + attachmentManagement.handlePastImageEvent(this, storageKey, noteKey, dataTransferItem) } else if (this.props.fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) { this.handlePasteUrl(e, editor, pastedTxt) } diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index 83509184e..6b47c0951 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -5,7 +5,7 @@ import styles from './MarkdownEditor.styl' import CodeEditor from 'browser/components/CodeEditor' import MarkdownPreview from 'browser/components/MarkdownPreview' import eventEmitter from 'browser/main/lib/eventEmitter' -import {findStorage} from 'browser/lib/findStorage' +import { findStorage } from 'browser/lib/findStorage' class MarkdownEditor extends React.Component { constructor (props) { @@ -223,7 +223,7 @@ class MarkdownEditor extends React.Component { } render () { - const { className, value, config, storageKey } = this.props + const {className, value, config, storageKey, noteKey} = this.props let editorFontSize = parseInt(config.editor.fontSize, 10) if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14 @@ -249,23 +249,24 @@ class MarkdownEditor extends React.Component { ? 'codeEditor' : 'codeEditor--hide' } - ref='code' - mode='GitHub Flavored Markdown' - value={value} - theme={config.editor.theme} - keyMap={config.editor.keyMap} - fontFamily={config.editor.fontFamily} - fontSize={editorFontSize} - indentType={config.editor.indentType} - indentSize={editorIndentSize} - enableRulers={config.editor.enableRulers} - rulers={config.editor.rulers} - displayLineNumbers={config.editor.displayLineNumbers} - scrollPastEnd={config.editor.scrollPastEnd} - storageKey={storageKey} - fetchUrlTitle={config.editor.fetchUrlTitle} - onChange={(e) => this.handleChange(e)} - onBlur={(e) => this.handleBlur(e)} + ref='code' + mode='GitHub Flavored Markdown' + value={value} + theme={config.editor.theme} + keyMap={config.editor.keyMap} + fontFamily={config.editor.fontFamily} + fontSize={editorFontSize} + indentType={config.editor.indentType} + indentSize={editorIndentSize} + enableRulers={config.editor.enableRulers} + rulers={config.editor.rulers} + displayLineNumbers={config.editor.displayLineNumbers} + scrollPastEnd={config.editor.scrollPastEnd} + storageKey={storageKey} + noteKey={noteKey} + fetchUrlTitle={config.editor.fetchUrlTitle} + onChange={(e) => this.handleChange(e)} + onBlur={(e) => this.handleBlur(e)} /> { this.fixDecodedURI(el) - el.href = this.markdown.normalizeLinkText(el.href) - if (!/\/:storage/.test(el.href)) return - el.href = `file:///${this.markdown.normalizeLinkText(path.join(storagePath, 'images', path.basename(el.href)))}` el.addEventListener('click', this.anchorClickHandler) }) @@ -409,12 +409,6 @@ export default class MarkdownPreview extends React.Component { el.addEventListener('click', this.linkClickHandler) }) - _.forEach(this.refs.root.contentWindow.document.querySelectorAll('img'), (el) => { - el.src = this.markdown.normalizeLinkText(el.src) - if (!/\/:storage/.test(el.src)) return - el.src = `file:///${this.markdown.normalizeLinkText(path.join(storagePath, 'images', path.basename(el.src)))}` - }) - codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme) ? codeBlockTheme : 'default' diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index c30f50dae..d82d4da3f 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -88,7 +88,7 @@ class MarkdownSplitEditor extends React.Component { } render () { - const { config, value, storageKey } = this.props + const {config, value, storageKey, noteKey} = this.props const storage = findStorage(storageKey) let editorFontSize = parseInt(config.editor.fontSize, 10) if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14 @@ -115,6 +115,7 @@ class MarkdownSplitEditor extends React.Component { scrollPastEnd={config.editor.scrollPastEnd} fetchUrlTitle={config.editor.fetchUrlTitle} storageKey={storageKey} + noteKey={noteKey} onChange={this.handleOnChange.bind(this)} onScroll={this.handleScroll.bind(this)} /> diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index 6f1f2f00b..1ef488a70 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -5,7 +5,7 @@ import math from '@rokt33r/markdown-it-math' import _ from 'lodash' import ConfigManager from 'browser/main/lib/ConfigManager' import katex from 'katex' -import {lastFindInArray} from './utils' +import { lastFindInArray } from './utils' function createGutter (str, firstLineNumber) { if (Number.isNaN(firstLineNumber)) firstLineNumber = 1 @@ -234,10 +234,6 @@ class Markdown { if (!_.isString(content)) content = '' return this.md.render(content) } - - normalizeLinkText (linkText) { - return this.md.normalizeLinkText(linkText) - } } export default Markdown diff --git a/browser/main/Detail/MarkdownNoteDetail.js b/browser/main/Detail/MarkdownNoteDetail.js index 6821bf2fa..b497a1dbd 100755 --- a/browser/main/Detail/MarkdownNoteDetail.js +++ b/browser/main/Detail/MarkdownNoteDetail.js @@ -288,6 +288,7 @@ class MarkdownNoteDetail extends React.Component { config={config} value={note.content} storageKey={note.storage} + noteKey={note.key} onChange={this.handleUpdateContent.bind(this)} ignorePreviewPointerEvents={ignorePreviewPointerEvents} /> @@ -297,6 +298,7 @@ class MarkdownNoteDetail extends React.Component { config={config} value={note.content} storageKey={note.storage} + noteKey={note.key} onChange={this.handleUpdateContent.bind(this)} ignorePreviewPointerEvents={ignorePreviewPointerEvents} /> diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js new file mode 100644 index 000000000..6d4d74061 --- /dev/null +++ b/browser/main/lib/dataApi/attachmentManagement.js @@ -0,0 +1,164 @@ +const uniqueSlug = require('unique-slug') +const fs = require('fs') +const path = require('path') +const findStorage = require('browser/lib/findStorage') +const mdurl = require('mdurl') + +const STORAGE_FOLDER_PLACEHOLDER = ':storage' +const DESTINATION_FOLDER = 'attachments' + +/** + * @description + * Copies a copy of an attachment to the storage folder specified by the given key and return the generated attachment name. + * Renames the file to match a unique file name. + * + * @param {String} sourceFilePath The source path of the attachment to be copied + * @param {String} storageKey Storage key of the destination storage + * @param {String} noteKey Key of the current note. Will be used as subfolder in :storage + * @param {boolean} useRandomName determines whether a random filename for the new file is used. If false the source file name is used + * @return {Promise} name (inclusive extension) of the generated file + */ +function copyAttachment (sourceFilePath, storageKey, noteKey, useRandomName = true) { + return new Promise((resolve, reject) => { + if (!sourceFilePath) { + reject('sourceFilePath has to be given') + } + + if (!storageKey) { + reject('storageKey has to be given') + } + + if (!noteKey) { + reject('noteKey has to be given') + } + + try { + if (!fs.existsSync(sourceFilePath)) { + reject('source file does not exist') + } + + const targetStorage = findStorage.findStorage(storageKey) + + const inputFile = fs.createReadStream(sourceFilePath) + let destinationName + if (useRandomName) { + destinationName = `${uniqueSlug()}${path.extname(sourceFilePath)}` + } else { + destinationName = path.basename(sourceFilePath) + } + const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + createAttachmentDestinationFolder(targetStorage.path, noteKey) + const outputFile = fs.createWriteStream(path.join(destinationDir, destinationName)) + inputFile.pipe(outputFile) + resolve(destinationName) + } catch (e) { + return reject(e) + } + }) +} + +function createAttachmentDestinationFolder (destinationStoragePath, noteKey) { + let destinationDir = path.join(destinationStoragePath, DESTINATION_FOLDER) + if (!fs.existsSync(destinationDir)) { + fs.mkdirSync(destinationDir) + } + destinationDir = path.join(destinationStoragePath, DESTINATION_FOLDER, noteKey) + if (!fs.existsSync(destinationDir)) { + fs.mkdirSync(destinationDir) + } +} + +/** + * @description Fixes the URLs embedded in the generated HTML so that they again refer actual local files. + * @param {String} renderedHTML HTML in that the links should be fixed + * @param {String} storagePath Path of the current storage + * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths. + */ +function fixLocalURLS (renderedHTML, storagePath) { + return renderedHTML.replace(new RegExp(mdurl.encode(path.sep), 'g'), path.sep).replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER)) +} + +/** + * @description Generates the markdown code for a given attachment + * @param {String} fileName Name of the attachment + * @param {String} path Path of the attachment + * @param {Boolean} showPreview Indicator whether the generated markdown should show a preview of the image. Note that at the moment only previews for images are supported + * @returns {String} Generated markdown code + */ +function generateAttachmentMarkdown (fileName, path, showPreview) { + return `${showPreview ? '!' : ''}[${fileName}](${path})` +} + +/** + * @description Handles the drop-event of a file. Includes the necessary markdown code and copies the file to the corresponding storage folder. + * The method calls {CodeEditor#insertAttachmentMd()} to include the generated markdown at the needed place! + * @param {CodeEditor} codeEditor Markdown editor. Its insertAttachmentMd() method will be called to include the markdown code + * @param {String} storageKey Key of the current storage + * @param {String} noteKey Key of the current note + * @param {Event} dropEvent DropEvent + */ +function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) { + const file = dropEvent.dataTransfer.files[0] + const filePath = file.path + const originalFileName = path.basename(filePath) + const fileType = file['type'] + + copyAttachment(filePath, storageKey, noteKey).then((fileName) => { + let showPreview = fileType.startsWith('image') + let imageMd = generateAttachmentMarkdown(originalFileName, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName), showPreview) + codeEditor.insertAttachmentMd(imageMd) + }) +} + +/** + * @description Creates a new file in the storage folder belonging to the current note and inserts the correct markdown code + * @param {CodeEditor} codeEditor Markdown editor. Its insertAttachmentMd() method will be called to include the markdown code + * @param {String} storageKey Key of the current storage + * @param {String} noteKey Key of the current note + * @param {DataTransferItem} dataTransferItem Part of the past-event + */ +function handlePastImageEvent (codeEditor, storageKey, noteKey, dataTransferItem) { + if (!codeEditor) { + throw new Error('codeEditor has to be given') + } + if (!storageKey) { + throw new Error('storageKey has to be given') + } + + if (!noteKey) { + throw new Error('noteKey has to be given') + } + if (!dataTransferItem) { + throw new Error('dataTransferItem has to be given') + } + + const blob = dataTransferItem.getAsFile() + const reader = new FileReader() + let base64data + const targetStorage = findStorage.findStorage(storageKey) + const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey) + createAttachmentDestinationFolder(targetStorage.path, noteKey) + + let imageName = `${uniqueSlug()}.png` + const imagePath = path.join(destinationDir, imageName) + + reader.onloadend = function () { + base64data = reader.result.replace(/^data:image\/png;base64,/, '') + base64data += base64data.replace('+', ' ') + const binaryData = new Buffer(base64data, 'base64').toString('binary') + fs.writeFile(imagePath, binaryData, 'binary') + let imageMd = generateAttachmentMarkdown(imageName, imagePath, true) + codeEditor.insertAttachmentMd(imageMd) + } + reader.readAsDataURL(blob) +} + +module.exports = { + copyAttachment, + fixLocalURLS, + generateAttachmentMarkdown, + handleAttachmentDrop, + handlePastImageEvent, + STORAGE_FOLDER_PLACEHOLDER, + DESTINATION_FOLDER +} diff --git a/browser/main/lib/dataApi/copyImage.js b/browser/main/lib/dataApi/copyImage.js index 6a79b8b73..73f64b7c0 100644 --- a/browser/main/lib/dataApi/copyImage.js +++ b/browser/main/lib/dataApi/copyImage.js @@ -2,6 +2,8 @@ const fs = require('fs') const path = require('path') const { findStorage } = require('browser/lib/findStorage') +//TODO: ehhc: delete this + /** * @description Copy an image and return the path. * @param {String} filePath diff --git a/browser/main/lib/dataApi/exportNote.js b/browser/main/lib/dataApi/exportNote.js index 313bb85b3..68ecf4edd 100755 --- a/browser/main/lib/dataApi/exportNote.js +++ b/browser/main/lib/dataApi/exportNote.js @@ -1,11 +1,12 @@ import copyFile from 'browser/main/lib/dataApi/copyFile' -import {findStorage} from 'browser/lib/findStorage' +import { findStorage } from 'browser/lib/findStorage' import filenamify from 'filenamify' const fs = require('fs') const path = require('path') const LOCAL_STORED_REGEX = /!\[(.*?)]\(\s*?\/:storage\/(.*\.\S*?)\)/gi +//TODO: ehhc: check this -> attachmentManagement const IMAGES_FOLDER_NAME = 'images' /** diff --git a/browser/main/lib/dataApi/moveNote.js b/browser/main/lib/dataApi/moveNote.js index 928d331b2..4528b8354 100644 --- a/browser/main/lib/dataApi/moveNote.js +++ b/browser/main/lib/dataApi/moveNote.js @@ -75,6 +75,7 @@ function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) { while (match != null) { const [, filename] = match const oldPath = path.join(oldStorage.path, 'images', filename) + //TODO: ehhc: attachmentManagement moveTasks.push( copyImage(oldPath, noteData.storage, false) .then(() => { diff --git a/package.json b/package.json index 038d4c00c..82c908968 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "striptags": "^2.2.1", "superagent": "^1.2.0", "superagent-promise": "^1.0.3", + "unique-slug": "2.0.0", "uuid": "^3.2.1" }, "devDependencies": { diff --git a/tests/dataApi/attachmentManagement.test.js b/tests/dataApi/attachmentManagement.test.js new file mode 100644 index 000000000..7e97cf807 --- /dev/null +++ b/tests/dataApi/attachmentManagement.test.js @@ -0,0 +1,168 @@ +'use strict' + +jest.mock('fs') +const fs = require('fs') +const path = require('path') +const findStorage = require('browser/lib/findStorage') +jest.mock('unique-slug') +const uniqueSlug = require('unique-slug') +const mdurl = require('mdurl') + +const systemUnderTest = require('browser/main/lib/dataApi/attachmentManagement') + +it('should test that copyAttachment should throw an error if sourcePath or storageKey or noteKey are undefined', function () { + systemUnderTest.copyAttachment(undefined, 'storageKey').then(() => {}, error => { + expect(error).toBe('sourceFilePath has to be given') + }) + systemUnderTest.copyAttachment(null, 'storageKey', 'noteKey').then(() => {}, error => { + expect(error).toBe('sourceFilePath has to be given') + }) + systemUnderTest.copyAttachment('source', undefined, 'noteKey').then(() => {}, error => { + expect(error).toBe('storageKey has to be given') + }) + systemUnderTest.copyAttachment('source', null, 'noteKey').then(() => {}, error => { + expect(error).toBe('storageKey has to be given') + }) + systemUnderTest.copyAttachment('source', 'storageKey', null).then(() => {}, error => { + expect(error).toBe('noteKey has to be given') + }) + systemUnderTest.copyAttachment('source', 'storageKey', undefined).then(() => {}, error => { + expect(error).toBe('noteKey has to be given') + }) +}) + +it('should test that copyAttachment should throw an error if sourcePath dosen\'t exists', function () { + fs.existsSync = jest.fn() + fs.existsSync.mockReturnValue(false) + + systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(() => {}, error => { + expect(error).toBe('source file does not exist') + expect(fs.existsSync).toHaveBeenCalledWith('path') + }) +}) + +it('should test that copyAttachment works correctly assuming correct working of fs', function () { + const dummyExtension = '.ext' + const sourcePath = 'path' + dummyExtension + const storageKey = 'storageKey' + const noteKey = 'noteKey' + const dummyUniquePath = 'dummyPath' + const dummyStorage = {path: 'dummyStoragePath'} + + fs.existsSync = jest.fn() + fs.existsSync.mockReturnValue(true) + fs.createReadStream = jest.fn() + fs.createReadStream.mockReturnValue({pipe: jest.fn()}) + fs.createWriteStream = jest.fn() + + findStorage.findStorage = jest.fn() + findStorage.findStorage.mockReturnValue(dummyStorage) + uniqueSlug.mockReturnValue(dummyUniquePath) + + systemUnderTest.copyAttachment(sourcePath, storageKey, noteKey).then( + function (newFileName) { + expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey) + expect(fs.createReadStream).toHaveBeenCalledWith(sourcePath) + expect(fs.existsSync).toHaveBeenCalledWith(sourcePath) + expect(fs.createReadStream().pipe).toHaveBeenCalled() + expect(fs.createWriteStream).toHaveBeenCalledWith(path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey, dummyUniquePath + dummyExtension)) + expect(newFileName).toBe(dummyUniquePath + dummyExtension) + }) +}) + +it('should test that copyAttachment creates a new folder if the attachment folder doesn\'t exist', function () { + const dummyStorage = {path: 'dummyStoragePath'} + const noteKey = 'noteKey' + const attachmentFolderPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER) + const attachmentFolderNoteKyPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey) + + fs.existsSync = jest.fn() + fs.existsSync.mockReturnValueOnce(true) + fs.existsSync.mockReturnValueOnce(false) + fs.existsSync.mockReturnValueOnce(false) + fs.mkdirSync = jest.fn() + + findStorage.findStorage = jest.fn() + findStorage.findStorage.mockReturnValue(dummyStorage) + uniqueSlug.mockReturnValue('dummyPath') + + systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then( + function () { + expect(fs.existsSync).toHaveBeenCalledWith(attachmentFolderPath) + expect(fs.mkdirSync).toHaveBeenCalledWith(attachmentFolderPath) + expect(fs.existsSync).toHaveBeenLastCalledWith(attachmentFolderNoteKyPath) + expect(fs.mkdirSync).toHaveBeenLastCalledWith(attachmentFolderNoteKyPath) + }) +}) + +it('should test that copyAttachment don\'t uses a random file name if not intended ', function () { + const dummyStorage = {path: 'dummyStoragePath'} + + fs.existsSync = jest.fn() + fs.existsSync.mockReturnValueOnce(true) + fs.existsSync.mockReturnValueOnce(false) + fs.mkdirSync = jest.fn() + + findStorage.findStorage = jest.fn() + findStorage.findStorage.mockReturnValue(dummyStorage) + uniqueSlug.mockReturnValue('dummyPath') + + systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey', false).then( + function (newFileName) { + expect(newFileName).toBe('path') + }) +}) + +it('should replace the all ":storage" path with the actual storage path', function () { + let storageFolder = systemUnderTest.DESTINATION_FOLDER + let testInput = + '\n' + + ' \n' + + ' //header\n' + + ' \n' + + ' \n' + + '

Headline

\n' + + '

\n' + + ' dummyImage.png\n' + + '

\n' + + '

\n' + + ' dummyPDF.pdf\n' + + '

\n' + + '

\n' + + ' dummyImage2.jpg\n' + + '

\n' + + ' \n' + + '' + let storagePath = '<>' + let expectedOutput = + '\n' + + ' \n' + + ' //header\n' + + ' \n' + + ' \n' + + '

Headline

\n' + + '

\n' + + ' dummyImage.png\n' + + '

\n' + + '

\n' + + ' dummyPDF.pdf\n' + + '

\n' + + '

\n' + + ' dummyImage2.jpg\n' + + '

\n' + + ' \n' + + '' + let actual = systemUnderTest.fixLocalURLS(testInput, storagePath) + expect(actual).toEqual(expectedOutput) +}) + +it('should test that generateAttachmentMarkdown works correct both with previews and without', function () { + let fileName = 'fileName' + let path = 'path' + let expected = `![${fileName}](${path})` + let actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, true) + expect(actual).toEqual(expected) + expected = `[${fileName}](${path})` + actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, false) + expect(actual).toEqual(expected) +}) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 62b6600af..a0e4d96f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8714,6 +8714,12 @@ uniqs@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" +unique-slug@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"