Inits FileUploadStore from current state in the filesystem

- Removes uploads when draft is deleted
- Misc fixes and renaming
This commit is contained in:
Juan Tejada 2016-01-26 18:48:21 -08:00
parent 752a749da7
commit 63d36a78c3
5 changed files with 60 additions and 26 deletions

View file

@ -441,7 +441,7 @@ class ComposerView extends React.Component
<button className="btn btn-toolbar btn-attach" style={order: 50}
title="Attach file"
onClick={@_selectFileForUpload}><RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
onClick={@_selectAttachment}><RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
<div style={order: 0, flex: 1} />
@ -506,6 +506,7 @@ class ComposerView extends React.Component
files: draft.files
subject: draft.subject
accounts: @_getAccountsForSend()
uploads: FileUploadStore.uploadsForMessage(@props.draftClientId) ? []
if !@state.populated
_.extend state,
@ -615,14 +616,14 @@ class ComposerView extends React.Component
_onDrop: (e) =>
# Accept drops of real files from other applications
for file in e.dataTransfer.files
Actions.attachFile({filePath: file.path, messageClientId: @props.draftClientId})
Actions.addAttachment({filePath: file.path, messageClientId: @props.draftClientId})
# Accept drops from attachment components / images within the app
if (uri = @_nonNativeFilePathForDrop(e))
Actions.attachFile({filePath: uri, messageClientId: @props.draftClientId})
Actions.addAttachment({filePath: uri, messageClientId: @props.draftClientId})
_onFilePaste: (path) =>
Actions.attachFile({filePath: path, messageClientId: @props.draftClientId})
Actions.addAttachment({filePath: path, messageClientId: @props.draftClientId})
_onChangeParticipants: (changes={}) =>
@_addToProxy(changes)
@ -744,8 +745,8 @@ class ComposerView extends React.Component
_destroyDraft: =>
Actions.destroyDraft(@props.draftClientId)
_selectFileForUpload: =>
Actions.selectFileForUpload({messageClientId: @props.draftClientId})
_selectAttachment: =>
Actions.selectAttachment({messageClientId: @props.draftClientId})
undo: (event) =>
event.preventDefault()

View file

@ -27,7 +27,7 @@ class FileUpload extends React.Component
</div>
_onClickRemove: =>
Actions.removeFileFromUpload @props.upload
Actions.removeAttachment @props.upload
_extension: =>
path.extname(@props.upload.filename)[1..-1]

View file

@ -445,9 +445,9 @@ class Actions
# File Actions
# Some file actions only need to be processed in their current window
@attachFile: ActionScopeWindow
@selectFileForUpload: ActionScopeWindow
@removeFileFromUpload: ActionScopeWindow
@addAttachment: ActionScopeWindow
@selectAttachment: ActionScopeWindow
@removeAttachment: ActionScopeWindow
@fetchAndOpenFile: ActionScopeWindow
@fetchAndSaveFile: ActionScopeWindow
@fetchFile: ActionScopeWindow

View file

@ -5,14 +5,16 @@ mkdirp = require 'mkdirp'
NylasStore = require 'nylas-store'
Actions = require '../actions'
Utils = require '../models/utils'
Message = require '../models/message'
DatabaseStore = require './database-store'
UPLOAD_DIR = path.join(NylasEnv.getConfigDirPath(), 'uploads')
class Upload
constructor: (@messageClientId, @originPath, @stats, @uploadDir = UPLOAD_DIR) ->
@id = Utils.generateTempId()
constructor: (@messageClientId, @originPath, @stats, @id, @uploadDir = UPLOAD_DIR) ->
@id ?= Utils.generateTempId()
@filename = path.basename(@originPath)
@draftUploadDir = path.join(@uploadDir, @messageClientId)
@targetDir = path.join(@draftUploadDir, @id)
@ -23,30 +25,38 @@ class Upload
class FileUploadStore extends NylasStore
constructor: ->
@listenTo Actions.selectFileForUpload, @_onSelectFileForUpload
@listenTo Actions.attachFile, @_onAttachFile
@listenTo Actions.removeFileFromUpload, @_onRemoveUpload
@listenTo Actions.selectAttachment, @_onSelectAttachment
@listenTo Actions.addAttachment, @_onAddAttachment
@listenTo Actions.removeAttachment, @_onRemoveAttachment
@listenTo DatabaseStore, @_onDataChanged
# We don't save uploads to the DB, we keep it in memory in the store.
# The key is the messageClientId. The value is a hash of paths and
# corresponding upload data.
@_fileUploads = {}
mkdirp(UPLOAD_DIR)
mkdirp.sync(UPLOAD_DIR)
@_fileUploads = @_getFileUploadsFromFs()
uploadsForMessage: (messageClientId) ->
@_fileUploads[messageClientId] ? []
_onSelectFileForUpload: ({messageClientId}) ->
# Handlers
_onDataChanged: (change) =>
return unless change.objectClass is Message.name and change.type is 'unpersist'
change.objects.forEach (message) =>
uploads = @_fileUploads[message.clientId]
if uploads?
uploads.forEach (upload) => @_onRemoveAttachment(upload)
_onSelectAttachment: ({messageClientId}) ->
@_verifyId(messageClientId)
# When the dialog closes, it triggers `Actions.attachFile`
# When the dialog closes, it triggers `Actions.addAttachment`
NylasEnv.showOpenDialog {properties: ['openFile', 'multiSelections']}, (pathsToOpen) ->
return if not pathsToOpen?
pathsToOpen = [pathsToOpen] if _.isString(pathsToOpen)
pathsToOpen.forEach (filePath) ->
Actions.attachFile({messageClientId, filePath})
Actions.addAttachment({messageClientId, filePath})
_onAttachFile: ({messageClientId, filePath}) ->
_onAddAttachment: ({messageClientId, filePath}) ->
@_verifyId(messageClientId)
@_getFileStats({messageClientId, filePath})
.then(@_makeUpload)
@ -56,7 +66,7 @@ class FileUploadStore extends NylasStore
.then(@_saveUpload)
.catch(@_onAttachFileError)
_onRemoveUpload: (upload) ->
_onRemoveAttachment: (upload) ->
return unless (@_fileUploads[upload.messageClientId] ? []).length > 0
@_deleteUpload(upload)
.then (upload) =>
@ -77,6 +87,29 @@ class FileUploadStore extends NylasStore
message: 'Cannot Attach File',
detail: message
# Helpers
_getTempIdDirsFor: (path) ->
fs.readdirSync(path).filter((dir) -> Utils.isTempId(dir))
_getFileUploadsFromFs: (rootDir = UPLOAD_DIR)->
# TODO This function makes my eyes hurt. Refactor
uploads = {}
dirs = @_getTempIdDirsFor(rootDir)
for messageClientId in dirs
uploads[messageClientId] = []
messageDir = path.join(rootDir, messageClientId)
uploadIds = @_getTempIdDirsFor(messageDir)
for uploadId in uploadIds
uploadDir = path.join(messageDir, uploadId)
for filename in fs.readdirSync(uploadDir)
uploadPath = path.join(uploadDir, filename)
stats = fs.statSync(uploadPath)
uploads[messageClientId].push(
new Upload(messageClientId, uploadPath, stats, uploadId)
)
return uploads
_verifyId: (messageClientId) ->
if messageClientId.blank?
throw new Error "You need to pass the ID of the message (draft) this Action refers to"

View file

@ -169,7 +169,7 @@ class SendDraftTask extends Task
# Remove attachments we were waiting to upload
# Call the Action to do this
for upload in @uploads
Actions.removeFileFromUpload(upload.messageClientId, upload.id)
Actions.removeAttachment(upload.messageClientId, upload.id)
return Promise.resolve(Task.Status.Success)