98 lines
2.8 KiB
JavaScript
98 lines
2.8 KiB
JavaScript
import { Controller } from "@hotwired/stimulus"
|
|
|
|
export default class UploadController extends Controller {
|
|
static values = {
|
|
siteId: Number,
|
|
};
|
|
|
|
upload(ev) {
|
|
ev.preventDefault();
|
|
|
|
this._promptForUpload((files) => {
|
|
this._doUploads(files);
|
|
})
|
|
}
|
|
|
|
_promptForUpload(onAccept) {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.accept = 'image/*';
|
|
input.multiple = true;
|
|
|
|
input.onchange = (e) => {
|
|
const files = Array.from(e.target.files);
|
|
if (files.length > 0) {
|
|
onAccept(files);
|
|
}
|
|
};
|
|
|
|
input.click();
|
|
}
|
|
|
|
async _doUploads(files) {
|
|
for (let file of files) {
|
|
await this._doUpload(file);
|
|
}
|
|
window.location.reload();
|
|
}
|
|
|
|
async _doUpload(file) {
|
|
console.log(`Uploading ${file.name}: new pending`);
|
|
|
|
// Prepare upload of file supplying size and mime-type
|
|
let newPending = await (await fetch(`/sites/${this.siteIdValue}/uploads/pending`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
size: file.size,
|
|
mime: file.type,
|
|
name: file.name,
|
|
})
|
|
})).json();
|
|
|
|
// Upload file in 2 MB blocks
|
|
let offset = 0;
|
|
let chunkSize = 2 * 1024 * 1024;
|
|
while (offset < file.size) {
|
|
let chunk = file.slice(offset, offset + chunkSize);
|
|
|
|
console.log(`Uploading ${file.name}: uploading part`);
|
|
await fetch(`/sites/${this.siteIdValue}/uploads/pending/${newPending.guid}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/octet-stream'
|
|
},
|
|
body: chunk
|
|
});
|
|
|
|
offset += chunkSize;
|
|
}
|
|
|
|
// Calculate SHA256 hash
|
|
const hash = await this._calculateSHA256(file);
|
|
|
|
// Finalise upload
|
|
console.log(`Uploading ${file.name}: finalise`);
|
|
await fetch(`/sites/${this.siteIdValue}/uploads/pending/${newPending.guid}/finalize`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
hash: hash
|
|
})
|
|
});
|
|
}
|
|
|
|
async _calculateSHA256(file) {
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
|
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
return hashHex;
|
|
}
|
|
} |