This is an automated email from the ASF dual-hosted git repository. machristie pushed a commit to branch airavata-3016 in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git
commit f56ca58345ab964709af10cec56077e9f48d2fb1 Author: Marcus Christie <[email protected]> AuthorDate: Sun May 26 13:58:32 2019 -0400 AIRAVATA-3032 Upload input files to tmp directory --- django_airavata/apps/api/data_products_helper.py | 22 ++++++++++++--- django_airavata/apps/api/datastore.py | 2 +- django_airavata/apps/api/urls.py | 1 + django_airavata/apps/api/views.py | 19 ++++++++++++- .../experiment/input-editors/FileInputEditor.vue | 31 ++++++++++++++-------- 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/django_airavata/apps/api/data_products_helper.py b/django_airavata/apps/api/data_products_helper.py index 785bb68..eb7f0ad 100644 --- a/django_airavata/apps/api/data_products_helper.py +++ b/django_airavata/apps/api/data_products_helper.py @@ -16,6 +16,7 @@ from airavata.model.data.replica.ttypes import ( from . import datastore, models logger = logging.getLogger(__name__) +TMP_INPUT_FILE_UPLOAD_DIR = "tmp" def save(request, path, file): @@ -26,6 +27,15 @@ def save(request, path, file): return data_product +def save_input_file_upload(request, file): + """Save input file in staging area for input file uploads.""" + username = request.user.username + file_name = os.path.basename(file.name) + full_path = datastore.save(username, TMP_INPUT_FILE_UPLOAD_DIR, file) + data_product = _save_data_product(request, full_path, name=file_name) + return data_product + + def open(request, data_product): "Return file object for replica if it exists in user storage." path = _get_replica_filepath(data_product) @@ -124,9 +134,10 @@ def _get_data_product_uri(request, full_path): return product_uri -def _save_data_product(request, full_path): +def _save_data_product(request, full_path, name=None): "Create, register and record in DB a data product for full_path." - data_product = _create_data_product(request.user.username, full_path) + data_product = _create_data_product( + request.user.username, full_path, name=name) product_uri = request.airavata_client.registerDataProduct( request.authz_token, data_product) data_product.productUri = product_uri @@ -147,11 +158,14 @@ def _delete_data_product(request, full_path): user_file.delete() -def _create_data_product(username, full_path): +def _create_data_product(username, full_path, name=None): data_product = DataProductModel() data_product.gatewayId = settings.GATEWAY_ID data_product.ownerName = username - file_name = os.path.basename(full_path) + if name is not None: + file_name = name + else: + file_name = os.path.basename(full_path) data_product.productName = file_name data_product.dataProductType = DataProductType.FILE data_replica_location = DataReplicaLocationModel() diff --git a/django_airavata/apps/api/datastore.py b/django_airavata/apps/api/datastore.py index aab6e8d..124949f 100644 --- a/django_airavata/apps/api/datastore.py +++ b/django_airavata/apps/api/datastore.py @@ -29,7 +29,7 @@ def open(username, path): def save(username, path, file): - """Save file to username/project name/experiment_name in data store.""" + """Save file to username/path in data store.""" # file.name may be full path, so get just the name of the file file_name = os.path.basename(file.name) user_data_storage = _user_data_storage(username) diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py index 9150e7c..6b80b19 100644 --- a/django_airavata/apps/api/urls.py +++ b/django_airavata/apps/api/urls.py @@ -49,6 +49,7 @@ urlpatterns = [ # url(r'^get-ufiles$', views.get_user_files, name='get_user_files'), # url(r'^upload-ufiles$', views.upload_user_file, name='upload_user_file'), # url(r'^delete-ufiles$', views.delete_user_file, name='delete_user_file'), + url(r'^upload$', views.upload_input_file, name='upload_input_file'), url(r'^download', views.download_file, name='download_file'), url(r'^delete-file$', views.delete_file, name='delete_file'), url(r'^data-products', views.DataProductView.as_view(), diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py index c93df77..819b16b 100644 --- a/django_airavata/apps/api/views.py +++ b/django_airavata/apps/api/views.py @@ -4,7 +4,7 @@ import os from django.conf import settings from django.contrib.auth.decorators import login_required from django.core.exceptions import ObjectDoesNotExist, PermissionDenied -from django.http import FileResponse, Http404, HttpResponse +from django.http import FileResponse, Http404, HttpResponse, JsonResponse from django.urls import reverse from rest_framework import mixins from rest_framework.decorators import action, detail_route, list_route @@ -858,6 +858,23 @@ class DataProductView(APIView): @login_required +def upload_input_file(request): + try: + input_file = request.FILES['file'] + data_product = data_products_helper.save_input_file_upload( + request, input_file) + serializer = serializers.DataProductSerializer( + data_product, context={'request': request}) + return JsonResponse({'uploaded': True, + 'data-product': serializer.data}) + except Exception as e: + log.error("Failed to upload file", exc_info=True) + resp = JsonResponse({'uploaded': False, 'error': str(e)}) + resp.status_code = 500 + return resp + + +@login_required def download_file(request): # TODO check that user has access to this file using sharing API data_product_uri = request.GET.get('data-product-uri', '') diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue index 84c1bcd..b37bf2a 100644 --- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue +++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue @@ -75,24 +75,33 @@ export default { }, deleteDataProduct() { utils.FetchUtils.delete( - "/api/delete-file?data-product-uri=" + encodeURIComponent(this.value) - ).then(() => { - this.data = null; - this.valueChanged(); - }); + "/api/delete-file?data-product-uri=" + encodeURIComponent(this.value), + { ignoreErrors: true } + ) + .then(() => { + this.data = null; + this.valueChanged(); + }) + .catch(err => { + // Ignore 404 Not Found errors, file no longer exists so assume was + // already deleted + if (err.details.status === 404) { + this.data = null; + this.valueChanged(); + } else { + throw err; + } + }) + .catch(err => utils.FetchUtils.reportError); }, fileChanged() { if (this.file) { let data = new FormData(); data.append("file", this.file); - data.append("project-id", this.experiment.projectId); - data.append("experiment-name", this.experiment.experimentName); this.$emit("uploadstart"); - // TODO: use the experimentDataDir off the experiment model as the path - // to upload to - utils.FetchUtils.post("/api/user-storage/~/tmp/", data, "", { showSpinner: false }) + utils.FetchUtils.post("/api/upload", data, "", { showSpinner: false }) .then(result => { - this.dataProduct = new models.DataProduct(result["uploaded"]); + this.dataProduct = new models.DataProduct(result["data-product"]); this.data = this.dataProduct.productUri; this.valueChanged(); })
