diff --git a/browser/main/lib/dataApi/moveNote.js b/browser/main/lib/dataApi/moveNote.js new file mode 100644 index 00000000..2c938aad --- /dev/null +++ b/browser/main/lib/dataApi/moveNote.js @@ -0,0 +1,92 @@ +const resolveStorageData = require('./resolveStorageData') +const _ = require('lodash') +const path = require('path') +const CSON = require('season') +const keygen = require('browser/lib/keygen') +const sander = require('sander') + +function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) { + let oldStorage, newStorage + try { + let cachedStorageList = JSON.parse(localStorage.getItem('storages')) + if (!_.isArray(cachedStorageList)) throw new Error('Storage doesn\'t exist.') + + oldStorage = _.find(cachedStorageList, {key: storageKey}) + if (oldStorage == null) throw new Error('Storage doesn\'t exist.') + + newStorage = _.find(cachedStorageList, {key: newStorageKey}) + if (newStorage == null) throw new Error('Target storage doesn\'t exist.') + } catch (e) { + return Promise.reject(e) + } + + return resolveStorageData(oldStorage) + .then(function saveNote (_oldStorage) { + oldStorage = _oldStorage + let noteData + let notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson') + try { + noteData = CSON.readFileSync(notePath) + } catch (err) { + console.warn('Failed to find note cson', err) + throw err + } + let newNoteKey + return Promise.resolve() + .then(function resolveNewStorage () { + if (storageKey === newStorageKey) { + newNoteKey = noteKey + return oldStorage + } + return resolveStorageData(newStorage) + .then(function findNewNoteKey (_newStorage) { + newStorage = _newStorage + newNoteKey = keygen() + let isUnique = false + while (!isUnique) { + try { + sander.statSync(path.join(newStorage.path, 'notes', newNoteKey + '.cson')) + newNoteKey = keygen() + } catch (err) { + if (err.code === 'ENOENT') { + isUnique = true + } else { + throw err + } + } + } + + return newStorage + }) + }) + .then(function checkFolderExistsAndPrepareNoteData (newStorage) { + if (_.find(newStorage.folders, {key: newFolderKey}) == null) throw new Error('Target folder doesn\'t exist.') + + noteData.folder = newFolderKey + noteData.key = newNoteKey + noteData.storage = newStorageKey + return noteData + }) + .then(function writeAndReturn (noteData) { + CSON.writeFileSync(path.join(newStorage.path, 'notes', noteData.key + '.cson'), _.omit(noteData, ['key', 'storage'])) + return { + oldStorageKey: storageKey, + oldNoteKey: noteKey, + note: noteData + } + }) + .then(function deleteOldNote (data) { + if (storageKey !== newStorageKey) { + try { + sander.unlinkSync(path.join(oldStorage.path, 'notes', noteKey + '.cson')) + } catch (err) { + console.warn(err) + } + } + + return data + }) + }) +} + +module.exports = moveNote diff --git a/tests/dataApi/moveNote.js b/tests/dataApi/moveNote.js new file mode 100644 index 00000000..2f9fccd1 --- /dev/null +++ b/tests/dataApi/moveNote.js @@ -0,0 +1,66 @@ +const test = require('ava') +const moveNote = require('browser/main/lib/dataApi/moveNote') + +global.document = require('jsdom').jsdom('') +global.window = document.defaultView +global.navigator = window.navigator + +const Storage = require('dom-storage') +const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const path = require('path') +const TestDummy = require('../fixtures/TestDummy') +const sander = require('sander') +const os = require('os') +const CSON = require('season') +const faker = require('faker') + +const storagePath = path.join(os.tmpdir(), 'test/move-note') +const storagePath2 = path.join(os.tmpdir(), 'test/move-note2') + +test.beforeEach((t) => { + t.context.storage1 = TestDummy.dummyStorage(storagePath) + t.context.storage2 = TestDummy.dummyStorage(storagePath2) + localStorage.setItem('storages', JSON.stringify([t.context.storage1.cache, t.context.storage2.cache])) +}) + +test.serial('Move a note', (t) => { + const storageKey1 = t.context.storage1.cache.key + const folderKey1 = t.context.storage1.json.folders[0].key + const note1 = t.context.storage1.notes[0] + const note2 = t.context.storage1.notes[1] + const storageKey2 = t.context.storage2.cache.key + const folderKey2 = t.context.storage2.json.folders[0].key + + return Promise.resolve() + .then(function doTest () { + return Promise.all([ + moveNote(storageKey1, note1.key, storageKey1, folderKey1), + moveNote(storageKey1, note2.key, storageKey2, folderKey2) + ]) + }) + .then(function assert (data) { + let data1 = data[0] + let data2 = data[1] + + let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.note.key + '.cson')) + + t.is(jsonData1.folder, folderKey1) + t.is(jsonData1.title, note1.title) + + let jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.note.key + '.cson')) + t.is(jsonData2.folder, folderKey2) + t.is(jsonData2.title, note2.title) + try { + CSON.readFileSync(path.join(storagePath, 'notes', note2.key + '.cson')) + t.fail('The old note should be deleted.') + } catch (err) { + t.is(err.code, 'ENOENT') + } + }) +}) + +test.after(function after () { + localStorage.clear() + sander.rimrafSync(storagePath) + sander.rimrafSync(storagePath2) +})