From fa002b82a532baebe24e9da06ea0af271408abf8 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Thu, 3 Mar 2016 18:00:37 -0800 Subject: [PATCH] fix(downloads): Replace stripped extensions, remember folder --- spec/stores/file-download-store-spec.coffee | 68 ++++++++++++++------- src/flux/stores/file-download-store.coffee | 23 ++++++- 2 files changed, 65 insertions(+), 26 deletions(-) diff --git a/spec/stores/file-download-store-spec.coffee b/spec/stores/file-download-store-spec.coffee index 1f670b7a0..a3075e4b7 100644 --- a/spec/stores/file-download-store-spec.coffee +++ b/spec/stores/file-download-store-spec.coffee @@ -247,8 +247,8 @@ describe "FileDownloadStore", -> describe "_fetchAndSave", -> beforeEach -> - @savePath = "/Users/imaginary/.nylas/Downloads/b.png" - spyOn(NylasEnv, 'showSaveDialog').andCallFake (options, callback) => callback(@savePath) + @userSelectedPath = "/Users/imaginary/.nylas/Downloads/b.png" + spyOn(NylasEnv, 'showSaveDialog').andCallFake (options, callback) => callback(@userSelectedPath) it "should open a save dialog and prompt the user to choose a download path", -> spyOn(FileDownloadStore, '_runDownload').andCallFake => @@ -257,27 +257,6 @@ describe "FileDownloadStore", -> expect(NylasEnv.showSaveDialog).toHaveBeenCalled() expect(FileDownloadStore._runDownload).toHaveBeenCalledWith(@testfile) - it "should copy the file to the download path after it's been downloaded and open it after the stream has ended", -> - download = {targetPath: @savePath} - onEndEventCallback = null - streamStub = - pipe: -> - on: (eventName, eventCallback) => - onEndEventCallback = eventCallback - - spyOn(FileDownloadStore, '_runDownload').andCallFake => - Promise.resolve(download) - spyOn(fs, 'createReadStream').andReturn(streamStub) - spyOn(fs, 'createWriteStream') - - FileDownloadStore._fetchAndSave(@testfile) - advanceClock(1) - expect(fs.createReadStream).toHaveBeenCalledWith(download.targetPath) - expect(shell.showItemInFolder).not.toHaveBeenCalled() - onEndEventCallback() - advanceClock(1) - expect(shell.showItemInFolder).toHaveBeenCalledWith(download.targetPath) - it "should open an error if the download fails", -> spyOn(FileDownloadStore, '_presentError') spyOn(FileDownloadStore, '_runDownload').andCallFake => @@ -286,6 +265,49 @@ describe "FileDownloadStore", -> advanceClock(1) expect(FileDownloadStore._presentError).toHaveBeenCalled() + describe "when the user confirms a path", -> + beforeEach -> + @download = {targetPath: 'bla'} + @onEndEventCallback = null + streamStub = + pipe: -> + on: (eventName, eventCallback) => + @onEndEventCallback = eventCallback + + spyOn(FileDownloadStore, '_runDownload').andCallFake => + Promise.resolve(@download) + spyOn(fs, 'createReadStream').andReturn(streamStub) + spyOn(fs, 'createWriteStream') + + it "should copy the file to the download path after it's been downloaded and open it after the stream has ended", -> + FileDownloadStore._fetchAndSave(@testfile) + advanceClock(1) + expect(fs.createReadStream).toHaveBeenCalledWith(@download.targetPath) + expect(shell.showItemInFolder).not.toHaveBeenCalled() + @onEndEventCallback() + advanceClock(1) + expect(shell.showItemInFolder).toHaveBeenCalledWith(@userSelectedPath) + + it "should update the NylasEnv.savedState.lastDownloadDirectory", -> + NylasEnv.savedState.lastDownloadDirectory = null + @userSelectedPath = "/Users/imaginary/.nylas/Another Random Folder/file.jpg" + FileDownloadStore._fetchAndSave(@testfile) + advanceClock(1) + expect(NylasEnv.savedState.lastDownloadDirectory).toEqual('/Users/imaginary/.nylas/Another Random Folder') + + describe "file extensions", -> + it "should allow the user to save the file with a different extension", -> + @userSelectedPath = "/Users/imaginary/.nylas/Downloads/b-changed.tiff" + FileDownloadStore._fetchAndSave(@testfile) + advanceClock(1) + expect(fs.createWriteStream).toHaveBeenCalledWith(@userSelectedPath) + + it "should restore the extension if the user removed it entirely, because it's usually an accident", -> + @userSelectedPath = "/Users/imaginary/.nylas/Downloads/b-changed" + FileDownloadStore._fetchAndSave(@testfile) + advanceClock(1) + expect(fs.createWriteStream).toHaveBeenCalledWith("#{@userSelectedPath}.png") + describe "_abortFetchFile", -> beforeEach -> @download = diff --git a/src/flux/stores/file-download-store.coffee b/src/flux/stores/file-download-store.coffee index 303a67caa..16134e82f 100644 --- a/src/flux/stores/file-download-store.coffee +++ b/src/flux/stores/file-download-store.coffee @@ -210,8 +210,19 @@ FileDownloadStore = Reflux.createStore @_presentError(file) _fetchAndSave: (file) -> - NylasEnv.showSaveDialog {defaultPath: @_defaultSavePath(file)}, (savePath) => + defaultPath = @_defaultSavePath(file) + defaultExtension = path.extname(defaultPath) + + NylasEnv.showSaveDialog {defaultPath: defaultPath}, (savePath) => return unless savePath + NylasEnv.savedState.lastDownloadDirectory = path.dirname(savePath) + + saveExtension = path.extname(savePath) + didLoseExtension = defaultExtension isnt '' and saveExtension is '' + if didLoseExtension + savePath = savePath + defaultExtension + + defaultPath = NylasEnv.savedState.lastDownloadDirectory @_runDownload(file).then (download) -> stream = fs.createReadStream(download.targetPath) stream.pipe(fs.createWriteStream(savePath)) @@ -236,13 +247,19 @@ FileDownloadStore = Reflux.createStore _defaultSavePath: (file) -> if process.platform is 'win32' home = process.env.USERPROFILE - else home = process.env.HOME + else + home = process.env.HOME downloadDir = path.join(home, 'Downloads') if not fs.existsSync(downloadDir) downloadDir = os.tmpdir() - path.join(downloadDir, file.displayName()) + if NylasEnv.savedState.lastDownloadDirectory + if fs.existsSync(NylasEnv.savedState.lastDownloadDirectory) + downloadDir = NylasEnv.savedState.lastDownloadDirectory + + filesafeName = file.displayName().replace(RegExpUtils.illegalPathCharactersRegexp(), '-') + path.join(downloadDir, filesafeName) _presentError: (file) -> dialog = require('remote').require('dialog')