Skip to content

Commit 50ed3f2

Browse files
iberryfulib-steffen
authored andcommitted
Download all archives in one click (#219)
* implement api for download all archive * implement ui for download all archive
1 parent fd36485 commit 50ed3f2

3 files changed

Lines changed: 78 additions & 2 deletions

File tree

src/api/handlers/projects/jobs.py

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
import os
33
import uuid
44
import re
5+
import tarfile
6+
import shutil
57

68
from io import BytesIO
79

810
import requests
911

10-
from flask import g, abort, Response, send_file, request
12+
from flask import g, abort, Response, send_file, request, after_this_request
1113
from flask_restplus import Resource, fields
1214

13-
from pyinfraboxutils import get_logger
15+
from pyinfraboxutils import get_logger, get_env
1416
from pyinfraboxutils.ibflask import OK
1517
from pyinfraboxutils.ibrestplus import api, response_model
1618
from pyinfraboxutils.storage import storage
@@ -444,6 +446,62 @@ def get(self, project_id, job_id):
444446
return result['archive']
445447

446448

449+
@ns.route('/<job_id>/archive/download/all')
450+
@api.response(403, 'Not Authorized')
451+
class ArchiveDownloadAll(Resource):
452+
453+
def get(self, project_id, job_id):
454+
'''
455+
Returns all archives
456+
'''
457+
result = g.db.execute_one_dict('''
458+
SELECT archive
459+
FROM job
460+
WHERE id = %s
461+
AND project_id = %s
462+
''', [job_id, project_id])
463+
464+
if not result or not result['archive']:
465+
abort(404)
466+
467+
base_path = os.path.join('/tmp', str(uuid.uuid4()))
468+
archive_dir = os.path.join(base_path, 'archive')
469+
os.mkdir(base_path)
470+
os.mkdir(archive_dir)
471+
472+
@after_this_request
473+
def _remove_file(response):
474+
if os.path.exists(base_path):
475+
shutil.rmtree(base_path)
476+
return response
477+
478+
for item in result['archive']:
479+
filename = item['filename']
480+
url = "%s/api/v1/projects/%s/jobs/%s/archive/download?filename=%s" % \
481+
(get_env('INFRABOX_ROOT_URL'), project_id, job_id, filename)
482+
try:
483+
token = encode_user_token(g.token['user']['id'])
484+
except Exception:
485+
#public project has no token here.
486+
token = ""
487+
headers = {'Authorization': 'bearer ' + token}
488+
489+
r = requests.get(url, headers=headers, timeout=120, verify=False)
490+
if r.status_code != 200:
491+
continue
492+
493+
with open(os.path.join(archive_dir, os.path.basename(filename)), 'w') as f:
494+
f.write(r.content)
495+
496+
if not os.listdir(archive_dir):
497+
abort(404)
498+
499+
tar_file = os.path.join(base_path, 'archive_%s' % job_id +'.tar.gz')
500+
with tarfile.open(tar_file, mode='w:gz') as archive:
501+
archive.add(archive_dir, arcname='archive')
502+
503+
return send_file(tar_file, as_attachment=True, attachment_filename=os.path.basename(tar_file))
504+
447505
@ns.route('/<job_id>/console')
448506
@api.response(403, 'Not Authorized')
449507
class Console(Resource):

src/dashboard-client/src/components/job/JobDetail.vue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@
8989
<md-icon>insert_drive_file</md-icon><span class="m-l-xs">Data Output</span>
9090
<md-tooltip md-direction="bottom">Data Output</md-tooltip>
9191
</md-button>
92+
<md-button class="md-raised md-primary md-dense" v-on:click="downloadAllArchive()" :disabled="job.state=='running'||job.state=='queued'||job.state=='scheduled'">
93+
<md-icon>insert_drive_file</md-icon><span class="m-l-xs">All Archive</span>
94+
<md-tooltip md-direction="bottom">All Archive</md-tooltip>
95+
</md-button>
9296
</md-layout>
9397
<md-layout md-align="start" md-vertical-align="start" md-flex-xsmall="100" md-flex-small="100" md-flex-medium="100" md-flex-large="100" md-flex-xlarge="100" md-hide-large-and-up>
9498
<md-table-card class="clean-card">
@@ -135,6 +139,12 @@
135139
<md-tooltip md-direction="bottom">Data Output</md-tooltip>
136140
</md-button>
137141
</div>
142+
<div class="m-r-xl">
143+
<md-button class="md-icon-button md-primary md-raised md-dense" v-on:click="downloadAllArchive()" :disabled="job.state=='running'||job.state=='queued'||job.state=='scheduled'">
144+
<md-icon style="color: white">insert_drive_file</md-icon>
145+
<md-tooltip md-direction="bottom">All Archive</md-tooltip>
146+
</md-button>
147+
</div>
138148
<div class="m-r-xl">
139149
<md-menu md-size="4" class="bg-white">
140150
<md-button class="md-icon-button md-primary md-raised md-dense" md-menu-trigger>
@@ -310,6 +320,9 @@ export default {
310320
},
311321
downloadDataOutput () {
312322
this.job.downloadDataOutput()
323+
},
324+
downloadAllArchive () {
325+
this.job.downloadAllArchive()
313326
}
314327
}
315328
}

src/dashboard-client/src/models/Job.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ export default class Job {
309309
NewAPIService.openAPIUrl(url)
310310
}
311311

312+
downloadAllArchive () {
313+
const url = `projects/${this.project.id}/jobs/${this.id}/archive/download/all`
314+
NewAPIService.openAPIUrl(url)
315+
}
316+
312317
downloadArchive (filename) {
313318
const url = `projects/${this.project.id}/jobs/${this.id}/archive/download?filename=${filename}`
314319
NewAPIService.openAPIUrl(url)

0 commit comments

Comments
 (0)