You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2019/12/05 19:30:48 UTC

[airavata-django-portal] branch master updated: AIRAVATA-3281 Use mime-type when loading output files

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git


The following commit(s) were added to refs/heads/master by this push:
     new b6770e0  AIRAVATA-3281 Use mime-type when loading output files
b6770e0 is described below

commit b6770e0a13a35134d2c2aa61c5ea57872b3accea
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Thu Dec 5 14:30:29 2019 -0500

    AIRAVATA-3281 Use mime-type when loading output files
---
 .../js/models/ApplicationInterfaceDefinition.js    | 14 +++++-
 .../js/models/OutputDataObjectType.js              | 55 +++++++++++++---------
 django_airavata/apps/api/views.py                  | 15 ++++--
 .../output-displays/DefaultOutputDisplay.vue       | 17 ++++++-
 .../common/js/components/DataProductViewer.vue     | 16 ++++++-
 5 files changed, 84 insertions(+), 33 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
index 8aa28e2..d71e6f0 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationInterfaceDefinition.js
@@ -49,12 +49,22 @@ export default class ApplicationInterfaceDefinition extends BaseModel {
     const stdout = new OutputDataObjectType({
       name: "Standard-Out",
       type: DataType.STDOUT,
-      isRequired: true
+      isRequired: true,
+      metaData: {
+        "file-metadata": {
+          "mime-type": "text/plain"
+        }
+      }
     });
     const stderr = new OutputDataObjectType({
       name: "Standard-Error",
       type: DataType.STDERR,
-      isRequired: true
+      isRequired: true,
+      metaData: {
+        "file-metadata": {
+          "mime-type": "text/plain"
+        }
+      }
     });
     if (!this.applicationOutputs) {
       this.applicationOutputs = [];
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js b/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js
index 5aaad3b..81bfa50 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/OutputDataObjectType.js
@@ -1,41 +1,40 @@
-
-import BaseModel from './BaseModel';
-import DataType from './DataType';
-import uuidv4 from 'uuid/v4';
+import BaseModel from "./BaseModel";
+import DataType from "./DataType";
+import uuidv4 from "uuid/v4";
 
 const FIELDS = [
-  'name',
-  'value',
+  "name",
+  "value",
   {
-    name: 'type',
+    name: "type",
     type: DataType,
-    default: DataType.URI,
+    default: DataType.URI
   },
-  'applicationArgument',
+  "applicationArgument",
   {
-    name: 'isRequired',
-    type: 'boolean',
+    name: "isRequired",
+    type: "boolean",
     default: false
   },
   {
-    name: 'requiredToAddedToCommandLine',
-    type: 'boolean',
-    default: false,
+    name: "requiredToAddedToCommandLine",
+    type: "boolean",
+    default: false
   },
   {
-    name: 'dataMovement',
-    type: 'boolean',
+    name: "dataMovement",
+    type: "boolean",
     default: false
   },
-  'location',
-  'searchQuery',
+  "location",
+  "searchQuery",
   {
-    name: 'outputStreaming',
-    type: 'boolean',
+    name: "outputStreaming",
+    type: "boolean",
     default: false
   },
-  'storageResourceId',
-  'metaData'
+  "storageResourceId",
+  "metaData"
 ];
 
 export default class OutputDataObjectType extends BaseModel {
@@ -48,6 +47,16 @@ export default class OutputDataObjectType extends BaseModel {
   get key() {
     return this._key;
   }
+
+  get fileMetadata() {
+    return this.metaData ? this.metaData["file-metadata"] : null;
+  }
+
+  get fileMetadataMimeType() {
+    return this.fileMetadata && this.fileMetadata["mime-type"]
+      ? this.fileMetadata["mime-type"]
+      : null;
+  }
 }
 
-OutputDataObjectType.VALID_DATA_TYPES = DataType.values
+OutputDataObjectType.VALID_DATA_TYPES = DataType.values;
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 14ff2c3..c5d22cb 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -944,21 +944,28 @@ def tus_upload_finish(request):
 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', '')
+    force_download = 'download' in request.GET
     data_product = None
     try:
         data_product = request.airavata_client.getDataProduct(
             request.authz_token, data_product_uri)
+        mime_type = "application/octet-stream"  # default mime-type
+        if (data_product.productMetadata and
+                'mime-type' in data_product.productMetadata):
+            mime_type = data_product.productMetadata['mime-type']
+        # 'mime-type' url parameter overrides
+        mime_type = request.GET.get('mime-type', mime_type)
     except Exception as e:
         log.warning("Failed to load DataProduct for {}"
                     .format(data_product_uri), exc_info=True)
         raise Http404("data product does not exist") from e
     try:
         data_file = data_products_helper.open(request, data_product)
-        response = FileResponse(data_file,
-                                content_type="application/octet-stream")
+        response = FileResponse(data_file, content_type=mime_type)
         file_name = os.path.basename(data_file.name)
-        response['Content-Disposition'] = ('attachment; filename="{}"'
-                                           .format(file_name))
+        if mime_type == 'application/octet-stream' or force_download:
+            response['Content-Disposition'] = ('attachment; filename="{}"'
+                                               .format(file_name))
         return response
     except ObjectDoesNotExist as e:
         raise Http404(str(e)) from e
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue
index 088ff62..25c1804 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue
@@ -4,6 +4,7 @@
       v-for="dp in dataProducts"
       :data-product="dp"
       :key="dp.productUri"
+      :mime-type="fileMimeType"
     />
   </div>
 </template>
@@ -29,8 +30,20 @@ export default {
   },
   components: {
     "data-product-viewer": components.DataProductViewer
+  },
+  computed: {
+    fileMimeType() {
+      if (this.experimentOutput.fileMetadataMimeType) {
+        return this.experimentOutput.fileMetadataMimeType;
+      } else if (
+        this.experimentOutput.dataType === models.DataType.STDOUT ||
+        this.experimentOutput.dataType === models.DataType.STDERR
+      ) {
+        return "text/plain";
+      } else {
+        return null;
+      }
+    }
   }
 };
 </script>
-
-
diff --git a/django_airavata/static/common/js/components/DataProductViewer.vue b/django_airavata/static/common/js/components/DataProductViewer.vue
index cb9fd86..52f35f7 100644
--- a/django_airavata/static/common/js/components/DataProductViewer.vue
+++ b/django_airavata/static/common/js/components/DataProductViewer.vue
@@ -1,7 +1,7 @@
 <template>
 
-  <span v-if="dataProduct.downloadURL">
-    <a :href="dataProduct.downloadURL" class="action-link">
+  <span v-if="downloadURL">
+    <a :href="downloadURL" class="action-link">
       <i class="fa fa-download"></i>
       {{ filename }}
     </a>
@@ -21,6 +21,9 @@ export default {
     inputFile: {
       type: Boolean,
       default: false
+    },
+    mimeType: {
+      type: String
     }
   },
   computed: {
@@ -33,6 +36,15 @@ export default {
       } else {
         return this.dataProduct.filename;
       }
+    },
+    downloadURL() {
+      if (!this.dataProduct.downloadURL) {
+        return null;
+      } else if (this.mimeType) {
+        return `${this.dataProduct.downloadURL}&mime-type=${encodeURIComponent(this.mimeType)}`;
+      } else {
+        return this.dataProduct.downloadURL;
+      }
     }
   }
 };