atst/js/components/upload_input.js
dandds 0517bd1b0a Fix task order uploads.
Task order uploads and downloads were broken. Uploads were broken
because file content was eing read in as plaintext every time, resulting
in encoding issues. I updated the bundle to use the newer Azure JS SDK.
We can now use a method for uploading browser files directly without
having to read their content. This required a few small internal changes
to the upload component, since the response structure is different.

I also removed the `downloadUrl` method from the JS uploader since it
was not being used.

Downloads were broken because the method that generates the download
link was not updated to use the BlobSasPermissions class from the
updated Azure Python SDK.
2020-02-03 09:56:02 -05:00

151 lines
3.8 KiB
JavaScript

import { buildUploader } from '../lib/upload'
import { emitFieldChange } from '../lib/emitters'
import inputValidations from '../lib/input_validations'
function uploadResponseOkay(response) {
// check BlobUploadCommonResponse: https://docs.microsoft.com/en-us/javascript/api/@azure/storage-blob/blobuploadcommonresponse?view=azure-node-latest
// The upload operation is a PUT that should return a 201
// https://docs.microsoft.com/en-us/rest/api/storageservices/put-blob#status-code
return response._response.status === 201
}
export default {
name: 'uploadinput',
props: {
name: String,
filename: {
type: String,
},
objectName: {
type: String,
},
initialErrors: {
type: Boolean,
default: false,
},
portfolioId: {
type: String,
},
sizeLimit: {
type: Number,
},
},
data: function() {
return {
hasInitialData: !!this.filename,
attachment: this.filename || null,
changed: false,
uploadError: false,
sizeError: false,
filenameError: false,
downloadLink: '',
fileSizeLimit: this.sizeLimit,
}
},
created: async function() {
if (this.hasInitialData) {
this.downloadLink = await this.getDownloadLink(
this.filename,
this.objectName
)
}
},
methods: {
addAttachment: async function(e) {
this.clearErrors()
const file = e.target.files[0]
if (file.size > this.fileSizeLimit) {
this.sizeError = true
return
}
if (!this.validateFileName(file.name)) {
this.filenameError = true
return
}
const uploader = await this.getUploader()
const response = await uploader.upload(file)
if (uploadResponseOkay(response)) {
this.attachment = e.target.value
this.$refs.attachmentFilename.value = file.name
this.$refs.attachmentObjectName.value = response.objectName
this.$refs.attachmentInput.disabled = true
emitFieldChange(this)
this.changed = true
this.downloadLink = await this.getDownloadLink(
file.name,
uploader.objectName
)
} else {
emitFieldChange(this)
this.changed = true
this.uploadError = true
}
},
validateFileName: function(name) {
const regex = inputValidations.restrictedFileName.match
return regex.test(name)
},
removeAttachment: function(e) {
e.preventDefault()
this.attachment = null
if (this.$refs.attachmentInput) {
this.$refs.attachmentInput.value = null
this.$refs.attachmentInput.disabled = false
}
this.clearErrors()
this.changed = true
emitFieldChange(this)
},
clearErrors: function() {
this.uploadError = false
this.sizeError = false
},
getUploader: async function() {
return fetch(`/task_orders/${this.portfolioId}/upload_token`, {
credentials: 'include',
})
.then(response => response.json())
.then(({ token, objectName }) => buildUploader(token, objectName))
},
getDownloadLink: async function(filename, objectName) {
const { downloadLink } = await fetch(
`/task_orders/${
this.portfolioId
}/download_link?filename=${filename}&objectName=${objectName}`,
{ credentials: 'include' }
).then(r => r.json())
return downloadLink
},
},
computed: {
baseName: function() {
if (this.attachment) {
return this.attachment.split(/[\\/]/).pop()
}
},
hideInput: function() {
return this.hasInitialData && !this.changed
},
showErrors: function() {
return (
(!this.changed && this.initialErrors) ||
this.uploadError ||
this.sizeError ||
this.filenameError
)
},
valid: function() {
return !!this.attachment
},
},
}