Mercurial > libervia-web
comparison libervia/web/pages/_browser/file_uploader.py @ 1532:106945841fbc
_browser (album): moved code to upload file to a separate `file_uploader` module:
this way, uploading logic can be re-used elsewhere.
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 22 Jun 2023 16:36:01 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1531:d7c78722e4f8 | 1532:106945841fbc |
---|---|
1 import json | |
2 from bridge import Bridge | |
3 from browser import console as log, window | |
4 import dialog | |
5 from template import Template | |
6 bridge = Bridge() | |
7 | |
8 log.warning = log.warn | |
9 | |
10 | |
11 class FileUploader: | |
12 """Class handling HTTP upload and progress display""" | |
13 | |
14 def __init__(self, files_service, template_file, files_path=None, on_delete_cb=None): | |
15 self.files_service = files_service | |
16 self.files_path = files_path | |
17 self.item_tpl = Template(template_file) | |
18 self.on_delete_cb = on_delete_cb | |
19 self.uploaded = {} | |
20 | |
21 def on_progress(self, ev, item_elt): | |
22 if ev.lengthComputable: | |
23 percent = int(ev.loaded/ev.total*100) | |
24 self.update_progress(item_elt, percent) | |
25 | |
26 def on_load(self, file_, item_elt): | |
27 self.update_progress(item_elt, 100) | |
28 item_elt.classList.add("progress_finished") | |
29 item_elt.classList.remove("progress_started") | |
30 if self.on_delete_cb is not None: | |
31 delete_btn = item_elt.select_one('.action_delete') | |
32 if delete_btn is not None: | |
33 delete_btn.bind("click", self.on_delete_cb) | |
34 log.info(f"file {file_.name} uploaded correctly") | |
35 | |
36 def on_error(self, failure, file_, item_elt): | |
37 dialog.notification.show( | |
38 f"can't upload {file_.name}: {failure}", | |
39 level="error" | |
40 ) | |
41 | |
42 def update_progress(self, item_elt, new_value): | |
43 progress_elt = item_elt.select_one("progress") | |
44 if progress_elt is not None: | |
45 progress_elt.value = new_value | |
46 progress_elt.text = f"{new_value}%" | |
47 | |
48 def on_slot_cb(self, file_, upload_slot, item_elt): | |
49 put_url, get_url, headers = upload_slot | |
50 xhr = window.XMLHttpRequest.new() | |
51 xhr.open("PUT", put_url, True) | |
52 xhr.upload.bind('progress', lambda ev: self.on_progress(ev, item_elt)) | |
53 xhr.upload.bind('load', lambda ev: self.on_load(file_, item_elt)) | |
54 xhr.upload.bind('error', lambda ev: self.on_error(xhr.response, file_, item_elt)) | |
55 if self.files_path is not None: | |
56 xhr.setRequestHeader( | |
57 'Xmpp-File-Path', | |
58 window.encodeURIComponent(self.files_path) | |
59 ) | |
60 xhr.setRequestHeader('Xmpp-File-No-Http', "true") | |
61 xhr.send(file_) | |
62 | |
63 # we update file data with the get URL | |
64 file_data = json.loads(item_elt.getAttribute("data-file")) | |
65 file_data["url"] = get_url | |
66 item_elt.setAttribute("data-file", json.dumps(file_data)) | |
67 | |
68 def on_slot_eb(self, file_, failure, item_elt): | |
69 dialog.notification.show( | |
70 f"Can't get upload slot: {failure['message']}", | |
71 level="error" | |
72 ) | |
73 item_elt.remove() | |
74 | |
75 def upload_files(self, files, container_elt): | |
76 """Start file upload, and add item_tpl to container_elt""" | |
77 log.info(f"uploading {len(files)} files") | |
78 for file_ in files: | |
79 url = window.URL.createObjectURL(file_) | |
80 | |
81 file_data = { | |
82 "name": file_.name, | |
83 "mime_type": file_.type, | |
84 } | |
85 template_file_data = file_data.copy() | |
86 # we don't want to open the file on click, it's not yet the | |
87 # uploaded URL | |
88 template_file_data["url"] = url | |
89 # we have no thumb yet, so we use the whole image | |
90 # TODO: reduce image for preview | |
91 template_file_data["thumb_url"] = url | |
92 | |
93 item_elt = self.item_tpl.get_elt({ | |
94 "file": template_file_data, | |
95 "uploading": True, | |
96 }) | |
97 item_elt.setAttribute("data-file", json.dumps(file_data)) | |
98 item_elt.classList.add("progress_started") | |
99 container_elt <= item_elt | |
100 | |
101 bridge.file_http_upload_get_slot( | |
102 file_.name, | |
103 file_.size, | |
104 file_.type or '', | |
105 self.files_service, | |
106 callback=lambda upload_slot, file_=file_, item_elt=item_elt: | |
107 self.on_slot_cb(file_, upload_slot, item_elt), | |
108 errback=lambda failure, file_=file_, item_elt=item_elt: | |
109 self.on_slot_eb(file_, failure, item_elt), | |
110 ) |