improve download code UI, tidy up URL structure
This commit is contained in:
parent
86bdac20af
commit
8275b940ac
18
src/main.rs
18
src/main.rs
|
@ -10,6 +10,7 @@ use actix_web::{
|
|||
};
|
||||
use actix_web_actors::ws;
|
||||
use log::error;
|
||||
use serde::Deserialize;
|
||||
use store::FileStore;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
|
@ -17,20 +18,25 @@ const APP_NAME: &str = "transbeam";
|
|||
|
||||
type AppData = web::Data<RwLock<FileStore>>;
|
||||
|
||||
#[get("/download/{file_code}")]
|
||||
#[derive(Deserialize)]
|
||||
struct DownloadRequest {
|
||||
code: String,
|
||||
}
|
||||
|
||||
#[get("/download")]
|
||||
async fn handle_download(
|
||||
req: HttpRequest,
|
||||
path: web::Path<String>,
|
||||
download: web::Query<DownloadRequest>,
|
||||
data: AppData,
|
||||
) -> actix_web::Result<HttpResponse> {
|
||||
let file_code = path.into_inner();
|
||||
if !store::is_valid_storage_code(&file_code) {
|
||||
let code = &download.code;
|
||||
if !store::is_valid_storage_code(code) {
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
}
|
||||
let data = data.read().await;
|
||||
let info = data.lookup_file(&file_code);
|
||||
let info = data.lookup_file(code);
|
||||
if let Some(info) = info {
|
||||
let storage_path = store::storage_dir().join(file_code);
|
||||
let storage_path = store::storage_dir().join(code);
|
||||
let file = File::open(&storage_path)?;
|
||||
Ok(download::DownloadingFile {
|
||||
file,
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
<img src="images/site-icons/transbeam.svg" height="128">
|
||||
<h1>transbeam</h1>
|
||||
</div>
|
||||
|
||||
<noscript>This page requires Javascript :(</noscript>
|
||||
|
||||
<div id="message"></div>
|
||||
<div id="upload_controls">
|
||||
<div>
|
||||
|
@ -36,11 +33,11 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="download_link_container">
|
||||
<div id="download_link_main">
|
||||
<div>Download link: <span id="download_link"></span></div><div class="copy_button"></div>
|
||||
<div id="download_code_container">
|
||||
<div id="download_code_main">
|
||||
<div>Download code: <span id="download_code"></span></div><div class="copy_button"></div>
|
||||
</div>
|
||||
<div id="copied_message">Copied!</div>
|
||||
<div id="copied_message">Link copied!</div>
|
||||
</div>
|
||||
<div id="progress_container">
|
||||
<div id="progress"></div>
|
||||
|
@ -52,6 +49,17 @@
|
|||
<input type="file" multiple id="file_input"/>
|
||||
<span class="fake_button" id="file_input_message">Select files to upload...</span>
|
||||
</label>
|
||||
<div id="download">
|
||||
<form id="download_form" action="download" method="get">
|
||||
<div>
|
||||
<label>
|
||||
<h4>Or enter a code to download files:</h4>
|
||||
<input type="text" id="download_code_input" name="code" placeholder="Download code"/>
|
||||
</label>
|
||||
</div>
|
||||
<input id="download_button" type="submit" value="Download"/>
|
||||
</form>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<h5>(c) 2022 xenofem, MIT licensed</h5>
|
||||
<h5><a target="_blank" href="https://git.xeno.science/xenofem/transbeam">source</a></h5>
|
||||
|
|
|
@ -24,7 +24,7 @@ body.error #message {
|
|||
body.selecting #upload_controls { display: revert; }
|
||||
body.no_files #upload_controls { display: none; }
|
||||
|
||||
body.selecting #download_link_container { display: none; }
|
||||
body.selecting #download_code_container { display: none; }
|
||||
|
||||
#progress_container { display: none; }
|
||||
body.uploading #progress_container { display: revert; }
|
||||
|
@ -37,3 +37,6 @@ body.selecting .delete_button { display: revert; }
|
|||
|
||||
#file_input_container { display: none; }
|
||||
body.selecting #file_input_container { display: revert; }
|
||||
|
||||
#download { display: none; }
|
||||
body.no_files #download { display: revert; }
|
||||
|
|
|
@ -31,7 +31,7 @@ body {
|
|||
background-size: 0;
|
||||
}
|
||||
|
||||
#download_link_container {
|
||||
#download_code_container {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
|
@ -41,11 +41,11 @@ body {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
#download_link_container:hover {
|
||||
#download_code_container:hover {
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
#download_link_main {
|
||||
#download_code_main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
@ -60,7 +60,7 @@ body {
|
|||
mask-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#download_link_container:hover .copy_button {
|
||||
#download_code_container:hover .copy_button {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
|
@ -74,10 +74,10 @@ body {
|
|||
height: fit-content;
|
||||
display: none;
|
||||
}
|
||||
#download_link_container.copied #copied_message {
|
||||
#download_code_container.copied #copied_message {
|
||||
display: revert;
|
||||
}
|
||||
#download_link_container.copied #download_link_main {
|
||||
#download_code_container.copied #download_code_main {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ input[type="file"] {
|
|||
display: none;
|
||||
}
|
||||
|
||||
button, .fake_button {
|
||||
button, .fake_button, input[type="submit"] {
|
||||
font-size: 18px;
|
||||
color: #000;
|
||||
background-color: #ccc;
|
||||
|
@ -138,11 +138,11 @@ button, .fake_button {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover, .fake_button:hover {
|
||||
button:hover, .fake_button:hover, input[type="submit"]:hover {
|
||||
background-color: #aaa;
|
||||
}
|
||||
|
||||
button:disabled, input:disabled + .fake_button {
|
||||
button:disabled, input:disabled + .fake_button, input[type="submit"]:disabled {
|
||||
color: #666;
|
||||
background-color: #eee;
|
||||
border-color: #ddd;
|
||||
|
@ -153,6 +153,15 @@ button:disabled, input:disabled + .fake_button {
|
|||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#download {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
#download_code_input {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ let fileInput;
|
|||
let fileList;
|
||||
let uploadButton;
|
||||
let lifetimeInput;
|
||||
let downloadLink;
|
||||
let downloadCode;
|
||||
let progress;
|
||||
let progressBar;
|
||||
|
||||
|
@ -26,7 +26,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
fileList = document.getElementById('file_list');
|
||||
uploadButton = document.getElementById('upload');
|
||||
lifetimeInput = document.getElementById('lifetime');
|
||||
downloadLink = document.getElementById('download_link');
|
||||
downloadCode = document.getElementById('download_code');
|
||||
progress = document.getElementById('progress');
|
||||
progressBar = document.getElementById('progress_bar');
|
||||
|
||||
|
@ -38,13 +38,38 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
uploadButton.addEventListener('click', beginUpload);
|
||||
|
||||
const downloadLinkContainer = document.getElementById('download_link_container');
|
||||
downloadLinkContainer.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(downloadLink.textContent);
|
||||
downloadLinkContainer.className = 'copied';
|
||||
const downloadCodeContainer = document.getElementById('download_code_container');
|
||||
downloadCodeContainer.addEventListener('click', () => {
|
||||
const downloadUrl = new URL(`download?code=${downloadCode.textContent}`, window.location);
|
||||
navigator.clipboard.writeText(downloadUrl.href);
|
||||
downloadCodeContainer.className = 'copied';
|
||||
});
|
||||
downloadLinkContainer.addEventListener('mouseleave', () => {
|
||||
downloadLinkContainer.className = '';
|
||||
downloadCodeContainer.addEventListener('mouseleave', () => {
|
||||
downloadCodeContainer.className = '';
|
||||
});
|
||||
|
||||
const downloadCodeInput = document.getElementById('download_code_input');
|
||||
const downloadButton = document.getElementById('download_button');
|
||||
const downloadForm = document.getElementById('download_form');
|
||||
downloadCodeInput.addEventListener('beforeinput', (e) => {
|
||||
if (/^[a-zA-Z0-9-]+$/.test(e.data)) { return; }
|
||||
e.preventDefault();
|
||||
if (e.data === ' ') {
|
||||
downloadCodeInput.value += '-';
|
||||
}
|
||||
});
|
||||
const disableEnableDownload = () => { downloadButton.disabled = (downloadCodeInput.value === ''); };
|
||||
disableEnableDownload();
|
||||
downloadCodeInput.addEventListener('input', disableEnableDownload);
|
||||
downloadForm.addEventListener('submit', (e) => {
|
||||
if (downloadCodeInput.value === '') {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
downloadCodeInput.value = '';
|
||||
downloadButton.disabled = true;
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
updateFiles();
|
||||
|
@ -122,7 +147,9 @@ function beginUpload() {
|
|||
byteIndex = 0;
|
||||
bytesSent = 0;
|
||||
|
||||
socket = new WebSocket(`${window.location.protocol === 'http:' ? 'ws' : 'wss'}://${window.location.host}/upload`);
|
||||
let websocketUrl = new URL('upload', window.location);
|
||||
websocketUrl.protocol = (window.location.protocol === 'http:') ? 'ws:' : 'wss:';
|
||||
socket = new WebSocket(websocketUrl);
|
||||
socket.addEventListener('open', sendManifest);
|
||||
socket.addEventListener('message', handleMessage);
|
||||
socket.addEventListener('close', handleClose);
|
||||
|
@ -150,7 +177,7 @@ function handleMessage(msg) {
|
|||
return;
|
||||
}
|
||||
if (reply.type === 'ready') {
|
||||
downloadLink.textContent = `${window.location.origin}/download/${reply.code}`;
|
||||
downloadCode.textContent = reply.code;
|
||||
updateProgress();
|
||||
document.body.className = 'uploading';
|
||||
sendData();
|
||||
|
@ -252,7 +279,7 @@ function handleClose(e) {
|
|||
|
||||
function finishSending() {
|
||||
if (socket.bufferedAmount > 0) {
|
||||
window.setTimeout(finishSending, 1000);
|
||||
setTimeout(finishSending, 1000);
|
||||
return;
|
||||
}
|
||||
socket.close();
|
||||
|
|
Loading…
Reference in a new issue