Skip to content

Commit f10fa63

Browse files
committed
Move note with attachment to different storage Fix for #1788
1 parent 266323b commit f10fa63

File tree

7 files changed

+115
-64
lines changed

7 files changed

+115
-64
lines changed

browser/main/SideNav/StorageItem.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import i18n from 'browser/lib/i18n'
1414

1515
const { remote } = require('electron')
1616
const { Menu, dialog } = remote
17+
const escapeStringRegexp = require('escape-string-regexp')
18+
const path = require('path')
1719

1820
class StorageItem extends React.Component {
1921
constructor (props) {
@@ -201,7 +203,7 @@ class StorageItem extends React.Component {
201203
createdNoteData.forEach((newNote) => {
202204
dispatch({
203205
type: 'MOVE_NOTE',
204-
originNote: noteData.find((note) => note.content === newNote.content),
206+
originNote: noteData.find((note) => note.content === newNote.oldContent),
205207
note: newNote
206208
})
207209
})
@@ -223,7 +225,8 @@ class StorageItem extends React.Component {
223225
const { folderNoteMap, trashedSet } = data
224226
const SortableStorageItemChild = SortableElement(StorageItemChild)
225227
const folderList = storage.folders.map((folder, index) => {
226-
const isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key)))
228+
let folderRegex = new RegExp(escapeStringRegexp(path.sep) + 'storages' + escapeStringRegexp(path.sep) + storage.key + escapeStringRegexp(path.sep) + 'folders' + escapeStringRegexp(path.sep) + folder.key)
229+
const isActive = !!(location.pathname.match(folderRegex))
227230
const noteSet = folderNoteMap.get(storage.key + '-' + folder.key)
228231

229232
let noteCount = 0
@@ -253,7 +256,7 @@ class StorageItem extends React.Component {
253256
)
254257
})
255258

256-
const isActive = location.pathname.match(new RegExp('\/storages\/' + storage.key + '$'))
259+
const isActive = location.pathname.match(new RegExp(escapeStringRegexp(path.sep) + 'storages' + escapeStringRegexp(path.sep) + storage.key + '$'))
257260

258261
return (
259262
<div styleName={isFolded ? 'root--folded' : 'root'}

browser/main/lib/dataApi/attachmentManagement.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const fs = require('fs')
33
const path = require('path')
44
const findStorage = require('browser/lib/findStorage')
55
const mdurl = require('mdurl')
6+
const fse = require('fs-extra')
67
const escapeStringRegexp = require('escape-string-regexp')
78

89
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
@@ -180,6 +181,28 @@ function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
180181
return result
181182
}
182183

184+
/**
185+
* @description Moves the attachments of the current note to the new location.
186+
* Returns a modified version of the given content so that the links to the attachments point to the new note key.
187+
* @param {String} oldPath Source of the note to be moved
188+
* @param {String} newPath Destination of the note to be moved
189+
* @param {String} noteKey Old note key
190+
* @param {String} newNoteKey New note key
191+
* @param {String} noteContent Content of the note to be moved
192+
* @returns {String} Modified version of noteContent in which the paths of the attachments are fixed
193+
*/
194+
function moveAttachments (oldPath, newPath, noteKey, newNoteKey, noteContent) {
195+
const src = path.join(oldPath, DESTINATION_FOLDER, noteKey)
196+
const dest = path.join(newPath, DESTINATION_FOLDER, newNoteKey)
197+
if (fse.existsSync(src)) {
198+
fse.moveSync(src, dest)
199+
}
200+
if (noteContent) {
201+
return noteContent.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + noteKey, 'g'), path.join(STORAGE_FOLDER_PLACEHOLDER, newNoteKey))
202+
}
203+
return noteContent
204+
}
205+
183206
/**
184207
* @description Deletes all :storage and noteKey references from the given input.
185208
* @param input Input in which the references should be deleted
@@ -243,6 +266,7 @@ module.exports = {
243266
getAbsolutePathsOfAttachmentsInContent,
244267
removeStorageAndNoteReferences,
245268
deleteAttachmentsNotPresentInNote,
269+
moveAttachments,
246270
STORAGE_FOLDER_PLACEHOLDER,
247271
DESTINATION_FOLDER
248272
}

browser/main/lib/dataApi/copyImage.js

Lines changed: 0 additions & 38 deletions
This file was deleted.

browser/main/lib/dataApi/moveNote.js

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const CSON = require('@rokt33r/season')
66
const keygen = require('browser/lib/keygen')
77
const sander = require('sander')
88
const { findStorage } = require('browser/lib/findStorage')
9+
const attachmentManagement = require('./attachmentManagement')
910

1011
function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
1112
let oldStorage, newStorage
@@ -63,36 +64,20 @@ function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
6364
noteData.key = newNoteKey
6465
noteData.storage = newStorageKey
6566
noteData.updatedAt = new Date()
67+
noteData.oldContent = noteData.content
6668

6769
return noteData
6870
})
69-
.then(function moveImages (noteData) {
70-
if (oldStorage.path === newStorage.path) return noteData
71-
72-
const searchImagesRegex = /!\[.*\]\(:storage\/(.+)\)/gi
73-
let match = searchImagesRegex.exec(noteData.content)
74-
75-
const moveTasks = []
76-
while (match != null) {
77-
const [, filename] = match
78-
const oldPath = path.join(oldStorage.path, 'attachments', filename)
79-
const newPath = path.join(newStorage.path, 'attachments', filename)
80-
// TODO: ehhc: attachmentManagement
81-
moveTasks.push(
82-
sander.copyFile(oldPath).to(newPath)
83-
.then(() => {
84-
fs.unlinkSync(oldPath)
85-
})
86-
)
87-
88-
// find next occurence
89-
match = searchImagesRegex.exec(noteData.content)
71+
.then(function moveAttachments (noteData) {
72+
if (oldStorage.path === newStorage.path) {
73+
return noteData
9074
}
9175

92-
return Promise.all(moveTasks).then(() => noteData)
76+
noteData.content = attachmentManagement.moveAttachments(oldStorage.path, newStorage.path, noteKey, newNoteKey, noteData.content)
77+
return noteData
9378
})
9479
.then(function writeAndReturn (noteData) {
95-
CSON.writeFileSync(path.join(newStorage.path, 'notes', noteData.key + '.cson'), _.omit(noteData, ['key', 'storage']))
80+
CSON.writeFileSync(path.join(newStorage.path, 'notes', noteData.key + '.cson'), _.omit(noteData, ['key', 'storage', 'oldContent']))
9681
return noteData
9782
})
9883
.then(function deleteOldNote (data) {

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@
5757
"codemirror-mode-elixir": "^1.1.1",
5858
"electron-config": "^0.2.1",
5959
"electron-gh-releases": "^2.0.2",
60+
"escape-string-regexp": "^1.0.5",
6061
"filenamify": "^2.0.0",
6162
"flowchart.js": "^1.6.5",
6263
"font-awesome": "^4.3.0",
64+
"fs-extra": "^5.0.0",
6365
"i18n-2": "^0.7.2",
6466
"iconv-lite": "^0.4.19",
6567
"immutable": "^3.8.1",

tests/dataApi/attachmentManagement.test.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const findStorage = require('browser/lib/findStorage')
77
jest.mock('unique-slug')
88
const uniqueSlug = require('unique-slug')
99
const mdurl = require('mdurl')
10+
const fse = require('fs-extra')
1011

1112
const systemUnderTest = require('browser/main/lib/dataApi/attachmentManagement')
1213

@@ -312,3 +313,59 @@ it('should test that deleteAttachmentsNotPresentInNote does not delete reference
312313
}
313314
expect(fsUnlinkCallArguments.includes(path.join(attachmentFolderPath, dummyFilesInFolder[0]))).toBe(false)
314315
})
316+
317+
it('should test that moveAttachments moves attachments only if the source folder existed', function () {
318+
fse.existsSync = jest.fn(() => false)
319+
fse.moveSync = jest.fn()
320+
321+
const oldPath = 'oldPath'
322+
const newPath = 'newPath'
323+
const oldNoteKey = 'oldNoteKey'
324+
const newNoteKey = 'newNoteKey'
325+
const content = ''
326+
327+
const expectedSource = path.join(oldPath, systemUnderTest.DESTINATION_FOLDER, oldNoteKey)
328+
329+
systemUnderTest.moveAttachments(oldPath, newPath, oldNoteKey, newNoteKey, content)
330+
expect(fse.existsSync).toHaveBeenCalledWith(expectedSource)
331+
expect(fse.moveSync).not.toHaveBeenCalled()
332+
})
333+
334+
it('should test that moveAttachments moves attachments to the right destination', function () {
335+
fse.existsSync = jest.fn(() => true)
336+
fse.moveSync = jest.fn()
337+
338+
const oldPath = 'oldPath'
339+
const newPath = 'newPath'
340+
const oldNoteKey = 'oldNoteKey'
341+
const newNoteKey = 'newNoteKey'
342+
const content = ''
343+
344+
const expectedSource = path.join(oldPath, systemUnderTest.DESTINATION_FOLDER, oldNoteKey)
345+
const expectedDestination = path.join(newPath, systemUnderTest.DESTINATION_FOLDER, newNoteKey)
346+
347+
systemUnderTest.moveAttachments(oldPath, newPath, oldNoteKey, newNoteKey, content)
348+
expect(fse.existsSync).toHaveBeenCalledWith(expectedSource)
349+
expect(fse.moveSync).toHaveBeenCalledWith(expectedSource, expectedDestination)
350+
})
351+
352+
it('should test that moveAttachments returns a correct modified content version', function () {
353+
fse.existsSync = jest.fn()
354+
fse.moveSync = jest.fn()
355+
356+
const oldPath = 'oldPath'
357+
const newPath = 'newPath'
358+
const oldNoteKey = 'oldNoteKey'
359+
const newNoteKey = 'newNoteKey'
360+
const testInput =
361+
'Test input' +
362+
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNoteKey + path.sep + 'image.jpg](imageName}) \n' +
363+
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + oldNoteKey + path.sep + 'pdf.pdf](pdf})'
364+
const expectedOutput =
365+
'Test input' +
366+
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + 'image.jpg](imageName}) \n' +
367+
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + newNoteKey + path.sep + 'pdf.pdf](pdf})'
368+
369+
const actualContent = systemUnderTest.moveAttachments(oldPath, newPath, oldNoteKey, newNoteKey, testInput)
370+
expect(actualContent).toBe(expectedOutput)
371+
})

yarn.lock

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,14 @@ fs-extra@^1.0.0:
36373637
jsonfile "^2.1.0"
36383638
klaw "^1.0.0"
36393639

3640+
fs-extra@^5.0.0:
3641+
version "5.0.0"
3642+
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
3643+
dependencies:
3644+
graceful-fs "^4.1.2"
3645+
jsonfile "^4.0.0"
3646+
universalify "^0.1.0"
3647+
36403648
36413649
version "2.10.1"
36423650
resolved "https://registry.yarnpkg.com/fs-plus/-/fs-plus-2.10.1.tgz#3204781d7840611e6364e7b6fb058c96327c5aa5"
@@ -5309,6 +5317,12 @@ jsonfile@^2.0.0, jsonfile@^2.1.0:
53095317
optionalDependencies:
53105318
graceful-fs "^4.1.6"
53115319

5320+
jsonfile@^4.0.0:
5321+
version "4.0.0"
5322+
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
5323+
optionalDependencies:
5324+
graceful-fs "^4.1.6"
5325+
53125326
jsonify@~0.0.0:
53135327
version "0.0.0"
53145328
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
@@ -8734,6 +8748,10 @@ unique-temp-dir@^1.0.0:
87348748
os-tmpdir "^1.0.1"
87358749
uid2 "0.0.3"
87368750

8751+
universalify@^0.1.0:
8752+
version "0.1.1"
8753+
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
8754+
87378755
unpipe@~1.0.0:
87388756
version "1.0.0"
87398757
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"

0 commit comments

Comments
 (0)