diff --git a/.secrets.baseline b/.secrets.baseline index 7d5b6411..814fd704 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -1,9 +1,9 @@ { "exclude": { - "files": null, + "files": "^.secrets.baseline$", "lines": null }, - "generated_at": "2019-08-21T18:40:15Z", + "generated_at": "2019-08-28T19:50:39Z", "plugins_used": [ { "base64_limit": 4.5, @@ -38,7 +38,7 @@ "hashed_secret": "d141ce86b0584abb29ee7c24af9afb1e3d871f04", "is_secret": false, "is_verified": false, - "line_number": 145, + "line_number": 156, "type": "Secret Keyword" } ], @@ -60,6 +60,22 @@ "type": "Hex High Entropy String" } ], + "alembic/versions/fda6bd7e1b65_clin_delete_cascade.py": [ + { + "hashed_secret": "61d8937fb12b982e07b933c083d9014c34159723", + "is_secret": false, + "is_verified": false, + "line_number": 13, + "type": "Hex High Entropy String" + }, + { + "hashed_secret": "999a22300a564f9d2bdca555c2170465fd760ae3", + "is_secret": false, + "is_verified": false, + "line_number": 14, + "type": "Hex High Entropy String" + } + ], "atst.ini.example": [ { "hashed_secret": "abcdb568713c255c81376829da20004ba9463fd3", @@ -178,10 +194,11 @@ "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", "is_secret": false, "is_verified": false, - "line_number": 481, + "line_number": 523, "type": "Hex High Entropy String" } ] }, "version": "0.12.5" } + diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index aca1c543..201a6923 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -4,7 +4,8 @@ from flask import ( render_template, request as http_request, url_for, - current_app, + current_app as app, + jsonify, ) from . import task_orders_bp @@ -17,9 +18,7 @@ from atst.utils.flash import formatted_flash as flash def render_task_orders_edit(template, portfolio_id=None, task_order_id=None, form=None): - (token, object_name) = current_app.csp.files.get_token() - render_args = {"token": token, "object_name": object_name} - + render_args = {} if task_order_id: task_order = TaskOrders.get(task_order_id) portfolio_id = task_order.portfolio_id @@ -73,6 +72,15 @@ def update_task_order( ) +@task_orders_bp.route("/task_orders//upload-token") +@user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") +def upload_token(portfolio_id): + (token, object_name) = app.csp.files.get_token() + render_args = {"token": token, "objectName": object_name} + + return jsonify(render_args) + + @task_orders_bp.route("/task_orders//edit") @user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") def edit(task_order_id): diff --git a/js/components/upload_input.js b/js/components/upload_input.js index edf01450..428cb367 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -1,6 +1,3 @@ -import createNumberMask from 'text-mask-addons/dist/createNumberMask' -import { conformToMask } from 'vue-text-mask' - import { emitEvent } from '../lib/emitters' import FormMixin from '../mixins/form' import textinput from './text_input' @@ -20,12 +17,6 @@ export default { props: { name: String, - token: { - type: Object, - }, - objectName: { - type: String, - }, initialData: { type: String, }, @@ -40,6 +31,9 @@ export default { type: Boolean, default: true, }, + portfolioId: { + type: String, + }, }, data: function() { @@ -52,8 +46,7 @@ export default { } }, - created: function() { - this.uploader = buildUploader(this.token) + created: async function() { emitEvent('field-mount', this, { optional: this.optional, name: this.name, @@ -71,13 +64,12 @@ export default { return } - const response = await this.uploader.upload(file, this.objectName) - + const uploader = await this.getUploader() + const response = await uploader.upload(file) if (response.ok) { this.attachment = e.target.value this.$refs.attachmentFilename.value = file.name - this.$refs.attachmentObjectName.value = this.objectName - this.$refs.attachmentInput.disabled = true + this.$refs.attachmentObjectName.value = response.objectName } else { this.uploadError = true } @@ -111,6 +103,13 @@ export default { 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)) + }, }, computed: { diff --git a/js/lib/upload.js b/js/lib/upload.js index ff85ab4a..f2c5440b 100644 --- a/js/lib/upload.js +++ b/js/lib/upload.js @@ -2,13 +2,14 @@ import Azure from 'azure-storage' import 'whatwg-fetch' class AzureUploader { - constructor(accountName, containerName, sasToken) { + constructor(accountName, containerName, sasToken, objectName) { this.accountName = accountName this.containerName = containerName this.sasToken = sasToken.token + this.objectName = objectName } - async upload(file, objectName) { + async upload(file) { const blobService = Azure.createBlobServiceWithSas( `https://${this.accountName}.blob.core.windows.net`, this.sasToken @@ -27,14 +28,14 @@ class AzureUploader { fileReader.addEventListener('load', f => { blobService.createBlockBlobFromText( this.containerName, - `${objectName}`, + `${this.objectName}`, f.target.result, options, - function(err, result) { + (err, result) => { if (err) { resolve({ ok: false }) } else { - resolve({ ok: true }) + resolve({ ok: true, objectName: this.objectName }) } } ) @@ -45,11 +46,12 @@ class AzureUploader { } class AwsUploader { - constructor(presignedPost) { + constructor(presignedPost, objectName) { this.presignedPost = presignedPost + this.objectName = objectName } - async upload(file, objectName) { + async upload(file) { const form = new FormData() Object.entries(this.presignedPost.fields).forEach(([k, v]) => { form.append(k, v) @@ -57,34 +59,38 @@ class AwsUploader { form.append('file', file) form.set('x-amz-meta-filename', file.name) - return fetch(this.presignedPost.url, { + const response = await fetch(this.presignedPost.url, { method: 'POST', body: form, }) + + return { ok: response.ok, objectName: this.objectName } } } class MockUploader { - constructor(token) { + constructor(token, objectName) { this.token = token + this.objectName = objectName } async upload(file, objectName) { - return Promise.resolve({ ok: true }) + return Promise.resolve({ ok: true, objectName: this.objectName }) } } -export const buildUploader = token => { +export const buildUploader = (token, objectName) => { const cloudProvider = process.env.CLOUD_PROVIDER || 'mock' if (cloudProvider === 'aws') { - return new AwsUploader(token) + return new AwsUploader(token, objectName) } else if (cloudProvider === 'azure') { return new AzureUploader( process.env.AZURE_ACCOUNT_NAME, process.env.AZURE_CONTAINER_NAME, - token + token, + objectName ) } else { - return new MockUploader(token) + return new MockUploader(token, objectName) } } diff --git a/js/test_templates/upload_input_error_template.html b/js/test_templates/upload_input_error_template.html index 02256f0d..50c1c3ab 100644 --- a/js/test_templates/upload_input_error_template.html +++ b/js/test_templates/upload_input_error_template.html @@ -4,10 +4,9 @@ v-bind:initial-errors='true' v-bind:watch='false' + v-bind:portfolio-id="''" name='pdf' :optional='false' - v-bind:token='token' - v-bind:object-name='"object_name"' >
@@ -41,6 +40,9 @@ + Test Error Message diff --git a/js/test_templates/upload_input_template.html b/js/test_templates/upload_input_template.html index 70c73407..d572cfe1 100644 --- a/js/test_templates/upload_input_template.html +++ b/js/test_templates/upload_input_template.html @@ -4,10 +4,9 @@ v-bind:initial-data='initialvalue' v-bind:watch='false' + v-bind:portfolio-id="''" name='pdf' :optional='false' - v-bind:token='token' - v-bind:object-name='"object_name"' >
@@ -41,6 +40,9 @@ +
diff --git a/templates/components/upload_input.html b/templates/components/upload_input.html index a261ea21..c2cc176d 100644 --- a/templates/components/upload_input.html +++ b/templates/components/upload_input.html @@ -1,6 +1,6 @@ {% from "components/icon.html" import Icon %} -{% macro UploadInput(field, show_label=False, watch=False, token="", object_name="") -%} +{% macro UploadInput(field, portfolio_id, show_label=False, watch=False) -%}
diff --git a/templates/task_orders/step_1.html b/templates/task_orders/step_1.html index 843b8c0b..7de4ed9c 100644 --- a/templates/task_orders/step_1.html +++ b/templates/task_orders/step_1.html @@ -14,8 +14,7 @@ {% set next_button_text = "Next: Add TO Number" %} {% set step = "1" %} - {% block to_builder_form_field %} {{ TOFormStepHeader('task_orders.form.supporting_docs_header' | translate, 'task_orders.form.supporting_docs_text' | translate) }} - {{ UploadInput(form.pdf, watch=True, token=token, object_name=object_name) }} + {{ UploadInput(form.pdf, portfolio.id, watch=True) }} {% endblock %} diff --git a/tests/render_vue_component.py b/tests/render_vue_component.py index b502ea93..ab33303c 100644 --- a/tests/render_vue_component.py +++ b/tests/render_vue_component.py @@ -74,15 +74,11 @@ def test_make_checkbox_input_template(checkbox_input_macro, initial_value_form): def test_make_upload_input_template(upload_input_macro, task_order_form): - rendered_upload_macro = upload_input_macro( - task_order_form.pdf, token="token", object_name="object_name" - ) + rendered_upload_macro = upload_input_macro(task_order_form.pdf) write_template(rendered_upload_macro, "upload_input_template.html") def test_make_upload_input_error_template(upload_input_macro, task_order_form): task_order_form.validate() - rendered_upload_macro = upload_input_macro( - task_order_form.pdf, token="token", object_name="object_name" - ) + rendered_upload_macro = upload_input_macro(task_order_form.pdf) write_template(rendered_upload_macro, "upload_input_error_template.html")