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/08/29 14:39:08 UTC
[airavata-django-portal] branch master updated: AIRAVATA-3081
Integrate tus uploads with storage views
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 2546acc AIRAVATA-3081 Integrate tus uploads with storage views
2546acc is described below
commit 2546acc8ae2e598ea42abfde309190552d042b27
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Thu Aug 29 10:38:54 2019 -0400
AIRAVATA-3081 Integrate tus uploads with storage views
---
django_airavata/apps/api/data_products_helper.py | 8 ++++---
django_airavata/apps/api/views.py | 19 +++++++++++++++
.../components/experiment/input-editors/Uppy.vue | 26 +++++++++++++--------
.../js/containers/UserStorageContainer.vue | 27 +++++++++++++++-------
4 files changed, 60 insertions(+), 20 deletions(-)
diff --git a/django_airavata/apps/api/data_products_helper.py b/django_airavata/apps/api/data_products_helper.py
index 3a07699..1614acd 100644
--- a/django_airavata/apps/api/data_products_helper.py
+++ b/django_airavata/apps/api/data_products_helper.py
@@ -19,11 +19,12 @@ logger = logging.getLogger(__name__)
TMP_INPUT_FILE_UPLOAD_DIR = "tmp"
-def save(request, path, file):
+def save(request, path, file, name=None):
"Save file in path in the user's storage."
+ logger.debug("save name=" + name)
username = request.user.username
- full_path = datastore.save(username, path, file)
- data_product = _save_data_product(request, full_path)
+ full_path = datastore.save(username, path, file, name=name)
+ data_product = _save_data_product(request, full_path, name=name)
return data_product
@@ -178,6 +179,7 @@ def _get_data_product_uri(request, full_path):
def _save_data_product(request, full_path, name=None):
"Create, register and record in DB a data product for full_path."
+ logger.debug("_save_data_product name=" + name)
data_product = _create_data_product(
request.user.username, full_path, name=name)
product_uri = request.airavata_client.registerDataProduct(
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 866529a..9b0246b 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -1454,10 +1454,29 @@ class UserStoragePathView(APIView):
data_products_helper.create_user_dir(request, path)
data_product = None
+ # Handle direct upload
if 'file' in request.FILES:
user_file = request.FILES['file']
data_product = data_products_helper.save(
request, path, user_file)
+ # Handle a tus upload
+ elif 'uploadURL' in request.POST:
+ # TODO: factor out tus uploadURL parsing, retrieval
+ uploadURL = request.POST['uploadURL']
+ # file UUID is last path component in URL. For example:
+ # http://localhost:1080/files/2c44415fdb6259a22f425145b87d0840
+ upload_uuid = urlparse(uploadURL).path.split("/")[-1]
+ upload_bin_path = os.path.join(settings.TUS_DATA_DIR,
+ f"{upload_uuid}.bin")
+ log.debug(f"upload_bin_path={upload_bin_path}")
+ upload_info_path = os.path.join(settings.TUS_DATA_DIR,
+ f"{upload_uuid}.info")
+ with open(upload_info_path) as upload_info_file, \
+ open(upload_bin_path, "rb") as upload_file:
+ upload_info = json.load(upload_info_file)
+ filename = upload_info['MetaData']['filename']
+ data_product = data_products_helper.save(
+ request, path, upload_file, name=filename)
return self._create_response(request, path, uploaded=data_product)
def delete(self, request, path="/", format=None):
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/Uppy.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/Uppy.vue
index f77ca01..98c96c5 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/Uppy.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/Uppy.vue
@@ -43,23 +43,28 @@ export default {
destroyed() {
// TODO: tear down the Uppy instance
},
+ data() {
+ return {
+ uppy: null
+ }
+ },
methods: {
initUppy() {
- const uppy = Uppy({
+ this.uppy = Uppy({
// TODO: set id
autoProceed: true,
// TODO: add maxFileSize restriction
debug: true
});
- uppy.use(FileInput, { target: this.$refs.fileInput, pretty: false });
- uppy.use(StatusBar, {
+ this.uppy.use(FileInput, { target: this.$refs.fileInput, pretty: false });
+ this.uppy.use(StatusBar, {
target: this.$refs.statusBar,
hideUploadButton: true,
hideAfterFinish: false
});
if (this.settings.tusEndpoint) {
- uppy.use(Tus, { endpoint: this.settings.tusEndpoint });
- uppy.on("upload-success", (file, response) => {
+ this.uppy.use(Tus, { endpoint: this.settings.tusEndpoint });
+ this.uppy.on("upload-success", (file, response) => {
const data = new FormData();
data.append("uploadURL", response.uploadURL);
utils.FetchUtils.post(this.tusUploadFinishEndpoint, data, "", {
@@ -69,7 +74,7 @@ export default {
});
});
} else {
- uppy.use(XHRUpload, {
+ this.uppy.use(XHRUpload, {
endpoint: this.xhrUploadEndpoint,
withCredentials: true,
headers: {
@@ -77,16 +82,19 @@ export default {
},
fieldName: 'file'
});
- uppy.on("upload-success", (file, response) => {
+ this.uppy.on("upload-success", (file, response) => {
this.$emit("upload-success", response.body);
});
}
- uppy.on("upload", () => {
+ this.uppy.on("upload", () => {
this.$emit("upload-started");
});
- uppy.on("complete", () => {
+ this.uppy.on("complete", () => {
this.$emit("upload-finished");
});
+ },
+ reset() {
+ this.uppy.reset();
}
}
};
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue
index 567de2e..a47ff71 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue
@@ -17,14 +17,12 @@
:state="fileUploadState"
:invalid-feedback="fileUploadInvalidFeedback"
>
- <b-form-file
- v-model="file"
- ref="file-input"
- placeholder="Add file"
- @input="fileChanged"
- class="mb-2"
- :state="fileUploadState"
- ></b-form-file>
+ <uppy
+ ref="file-upload"
+ :xhr-upload-endpoint="uploadEndpoint"
+ :tus-upload-finish-endpoint="uploadEndpoint"
+ @upload-success="uploadSuccess"
+ />
</b-form-group>
</div>
<div class="col">
@@ -62,8 +60,13 @@
import { services, session, utils } from "django-airavata-api";
import { notifications } from "django-airavata-common-ui";
+import Uppy from "../components/experiment/input-editors/Uppy";
+
export default {
name: "user-storage-container",
+ components: {
+ Uppy
+ },
computed: {
storagePath() {
if (this.$route.path.startsWith("/")) {
@@ -114,6 +117,10 @@ export default {
} else {
return null;
}
+ },
+ uploadEndpoint() {
+ // This endpoint can handle XHR upload or a TUS uploadURL
+ return "/api/user-storage/" + this.storagePath;
}
},
data() {
@@ -166,6 +173,10 @@ export default {
});
}
},
+ uploadSuccess() {
+ this.$refs["file-upload"].reset();
+ this.loadUserStoragePath(this.storagePath);
+ },
addDirectory() {
if (this.dirName) {
let newDirPath = this.storagePath;