mirror of
https://github.com/Dangoware/confetti-box.git
synced 2025-04-19 15:22:57 -05:00
Properly set up time buttons on page
This commit is contained in:
parent
26f1f70a47
commit
34142ba721
7 changed files with 247 additions and 52 deletions
129
Cargo.lock
generated
129
Cargo.lock
generated
|
@ -122,6 +122,12 @@ dependencies = [
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "binascii"
|
name = "binascii"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
@ -244,6 +250,41 @@ version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -251,6 +292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -456,13 +498,19 @@ dependencies = [
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"indexmap",
|
"indexmap 2.6.0",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
|
@ -481,6 +529,12 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.12"
|
version = "0.2.12"
|
||||||
|
@ -573,6 +627,23 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
@ -580,7 +651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.0",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -740,6 +811,8 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"maud",
|
"maud",
|
||||||
"rocket",
|
"rocket",
|
||||||
|
"serde",
|
||||||
|
"serde_with",
|
||||||
"toml",
|
"toml",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
@ -1069,7 +1142,7 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"figment",
|
"figment",
|
||||||
"futures",
|
"futures",
|
||||||
"indexmap",
|
"indexmap 2.6.0",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"multer",
|
"multer",
|
||||||
|
@ -1101,7 +1174,7 @@ checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"devise",
|
"devise",
|
||||||
"glob",
|
"glob",
|
||||||
"indexmap",
|
"indexmap 2.6.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rocket_http",
|
"rocket_http",
|
||||||
|
@ -1121,7 +1194,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"hyper",
|
"hyper",
|
||||||
"indexmap",
|
"indexmap 2.6.0",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"pear",
|
"pear",
|
||||||
|
@ -1182,18 +1255,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.211"
|
version = "1.0.213"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ac55e59090389fb9f0dd9e0f3c09615afed1d19094284d0b200441f13550793"
|
checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.211"
|
version = "1.0.213"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "54be4f245ce16bc58d57ef2716271d0d4519e0f6defa147f6e081005bcb278ff"
|
checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1221,6 +1294,36 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.6.0",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
@ -1294,6 +1397,12 @@ dependencies = [
|
||||||
"loom",
|
"loom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.82"
|
version = "2.0.82"
|
||||||
|
@ -1438,7 +1547,7 @@ version = "0.22.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.6.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
|
|
@ -10,6 +10,8 @@ chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
maud = { version = "0.26", features = ["rocket"] }
|
maud = { version = "0.26", features = ["rocket"] }
|
||||||
rocket = { version = "0.5", features = ["json"] }
|
rocket = { version = "0.5", features = ["json"] }
|
||||||
|
serde = { version = "1.0.213", features = ["derive"] }
|
||||||
|
serde_with = { version = "3.11.0", features = ["chrono_0_4"] }
|
||||||
toml = "0.8.19"
|
toml = "0.8.19"
|
||||||
uuid = { version = "1.11.0", features = ["v4"] }
|
uuid = { version = "1.11.0", features = ["v4"] }
|
||||||
|
|
||||||
|
|
68
src/main.rs
68
src/main.rs
|
@ -4,7 +4,7 @@ mod settings;
|
||||||
|
|
||||||
use std::{path::{Path, PathBuf}, sync::{Arc, RwLock}, time::Duration};
|
use std::{path::{Path, PathBuf}, sync::{Arc, RwLock}, time::Duration};
|
||||||
use blake3::Hash;
|
use blake3::Hash;
|
||||||
use chrono::{DateTime, TimeDelta, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use database::{clean_loop, Database, MochiFile};
|
use database::{clean_loop, Database, MochiFile};
|
||||||
use log::info;
|
use log::info;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
|
@ -45,17 +45,20 @@ fn home() -> Markup {
|
||||||
(head("Mochi"))
|
(head("Mochi"))
|
||||||
|
|
||||||
center {
|
center {
|
||||||
div id="durationOptions" {
|
h1 { "Confetti Box" }
|
||||||
|
div id="durationBox" {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
form id="uploadForm" {
|
form id="uploadForm" {
|
||||||
label for="fileUpload" class="file_upload" onclick="document.getElementById('fileInput').click()" {
|
label for="fileUpload"
|
||||||
|
class="button"
|
||||||
|
onclick="document.getElementById('fileInput').click()"
|
||||||
|
{
|
||||||
"Upload File"
|
"Upload File"
|
||||||
}
|
}
|
||||||
input id="fileInput" type="file" name="fileUpload" onchange="formSubmit(this.parentNode)" style="display:none;";
|
input id="fileInput" type="file" name="fileUpload" onchange="formSubmit(this.parentNode)" style="display:none;";
|
||||||
br;
|
input id="fileDuration" type="text" name="duration" minlength="2" maxlength="7" value="" style="display:none;";
|
||||||
input type="text" name="duration" minlength="2" maxlength="4";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div class="progress_box" {
|
div class="progress_box" {
|
||||||
|
@ -64,13 +67,13 @@ fn home() -> Markup {
|
||||||
}
|
}
|
||||||
|
|
||||||
div id="uploadedFilesDisplay" {
|
div id="uploadedFilesDisplay" {
|
||||||
h2 class="sep center" { "Uploaded Files" }
|
h2 { "Uploaded Files" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromForm)]
|
#[derive(Debug, FromForm)]
|
||||||
struct Upload<'r> {
|
struct Upload<'r> {
|
||||||
#[field(name = "fileUpload")]
|
#[field(name = "fileUpload")]
|
||||||
file: TempFile<'r>,
|
file: TempFile<'r>,
|
||||||
|
@ -83,16 +86,22 @@ struct Upload<'r> {
|
||||||
#[post("/upload", data = "<file_data>")]
|
#[post("/upload", data = "<file_data>")]
|
||||||
async fn handle_upload(
|
async fn handle_upload(
|
||||||
mut file_data: Form<Upload<'_>>,
|
mut file_data: Form<Upload<'_>>,
|
||||||
db: &State<Arc<RwLock<Database>>>
|
db: &State<Arc<RwLock<Database>>>,
|
||||||
|
settings: &State<Settings>,
|
||||||
) -> Result<Json<ClientResponse>, std::io::Error> {
|
) -> Result<Json<ClientResponse>, std::io::Error> {
|
||||||
let mut out_path = PathBuf::from("files/");
|
let mut out_path = PathBuf::from("files/");
|
||||||
|
let mut temp_dir = settings.temp_dir.clone();
|
||||||
|
|
||||||
let expire_time = if let Ok(t) = parse_time_string(&file_data.expire_time) {
|
let expire_time = if let Ok(t) = parse_time_string(&file_data.expire_time) {
|
||||||
if t < TimeDelta::days(365) {
|
if t > settings.duration.maximum {
|
||||||
t
|
return Ok(Json(ClientResponse {
|
||||||
} else {
|
status: false,
|
||||||
TimeDelta::days(365)
|
response: "Duration larger than maximum",
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t
|
||||||
} else {
|
} else {
|
||||||
return Ok(Json(ClientResponse {
|
return Ok(Json(ClientResponse {
|
||||||
status: false,
|
status: false,
|
||||||
|
@ -101,13 +110,20 @@ async fn handle_upload(
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Properly sanitize this...
|
||||||
|
let raw_name = &*file_data.file
|
||||||
|
.raw_name()
|
||||||
|
.unwrap()
|
||||||
|
.dangerous_unsafe_unsanitized_raw()
|
||||||
|
.as_str()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
// Get temp path and hash it
|
// Get temp path and hash it
|
||||||
let temp_filename = "temp_files/".to_owned() + &Uuid::new_v4().to_string();
|
temp_dir.push(&Uuid::new_v4().to_string());
|
||||||
|
let temp_filename = temp_dir;
|
||||||
file_data.file.persist_to(&temp_filename).await?;
|
file_data.file.persist_to(&temp_filename).await?;
|
||||||
let hash = hash_file(&temp_filename).await?;
|
let hash = hash_file(&temp_filename).await?;
|
||||||
|
|
||||||
// TODO: Properly sanitize this...
|
|
||||||
let raw_name = file_data.file.raw_name().unwrap().dangerous_unsafe_unsanitized_raw().as_str();
|
|
||||||
let filename = get_id(
|
let filename = get_id(
|
||||||
raw_name,
|
raw_name,
|
||||||
hash.0
|
hash.0
|
||||||
|
@ -122,6 +138,10 @@ async fn handle_upload(
|
||||||
expire_time
|
expire_time
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if db.read().unwrap().files.contains_key(&constructed_file.get_key()) {
|
||||||
|
info!("Key already in DB");
|
||||||
|
}
|
||||||
|
|
||||||
// Move it to the new proper place
|
// Move it to the new proper place
|
||||||
std::fs::rename(temp_filename, out_path)?;
|
std::fs::rename(temp_filename, out_path)?;
|
||||||
|
|
||||||
|
@ -130,8 +150,8 @@ async fn handle_upload(
|
||||||
|
|
||||||
Ok(Json(ClientResponse {
|
Ok(Json(ClientResponse {
|
||||||
status: true,
|
status: true,
|
||||||
name: Some(constructed_file.name().clone()),
|
name: constructed_file.name().clone(),
|
||||||
url: Some("files/".to_string() + &filename),
|
url: "files/".to_string() + &filename,
|
||||||
expires: Some(constructed_file.get_expiry()),
|
expires: Some(constructed_file.get_expiry()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
|
@ -146,10 +166,10 @@ struct ClientResponse {
|
||||||
|
|
||||||
pub response: &'static str,
|
pub response: &'static str,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "String::is_empty")]
|
||||||
pub name: Option<String>,
|
pub name: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "String::is_empty")]
|
||||||
pub url: Option<String>,
|
pub url: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub expires: Option<DateTime<Utc>>,
|
pub expires: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
@ -181,9 +201,9 @@ async fn hash_file<P: AsRef<Path>>(input: &P) -> Result<(Hash, usize), std::io::
|
||||||
fn server_info(settings: &State<Settings>) -> Json<ServerInfo> {
|
fn server_info(settings: &State<Settings>) -> Json<ServerInfo> {
|
||||||
Json(ServerInfo {
|
Json(ServerInfo {
|
||||||
max_filesize: settings.max_filesize,
|
max_filesize: settings.max_filesize,
|
||||||
max_duration: settings.duration.maximum,
|
max_duration: settings.duration.maximum.num_seconds() as u32,
|
||||||
default_duration: settings.duration.default,
|
default_duration: settings.duration.default.num_seconds() as u32,
|
||||||
allowed_durations: settings.duration.allowed.clone(),
|
allowed_durations: settings.duration.allowed.clone().into_iter().map(|t| t.num_seconds() as u32).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::{fs::{self, File}, io::{self, Read, Write}, path::{Path, PathBuf}};
|
use std::{fs::{self, File}, io::{self, Read, Write}, path::{Path, PathBuf}};
|
||||||
|
|
||||||
|
use chrono::TimeDelta;
|
||||||
|
use serde_with::serde_as;
|
||||||
use rocket::serde::{Deserialize, Serialize};
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A response to the client from the server
|
/// A response to the client from the server
|
||||||
|
@ -10,6 +12,11 @@ pub struct Settings {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub max_filesize: u64,
|
pub max_filesize: u64,
|
||||||
|
|
||||||
|
/// Is overwiting already uploaded files with the same hash allowed, or is
|
||||||
|
/// this a no-op?
|
||||||
|
#[serde(default)]
|
||||||
|
pub overwrite: bool,
|
||||||
|
|
||||||
/// Settings pertaining to duration information
|
/// Settings pertaining to duration information
|
||||||
pub duration: DurationSettings,
|
pub duration: DurationSettings,
|
||||||
|
|
||||||
|
@ -34,6 +41,7 @@ impl Default for Settings {
|
||||||
Self {
|
Self {
|
||||||
max_filesize: 128_000_000, // 128 MB
|
max_filesize: 128_000_000, // 128 MB
|
||||||
duration: DurationSettings::default(),
|
duration: DurationSettings::default(),
|
||||||
|
overwrite: true,
|
||||||
server: ServerSettings::default(),
|
server: ServerSettings::default(),
|
||||||
path: "./settings.toml".into(),
|
path: "./settings.toml".into(),
|
||||||
database_path: "./database.mochi".into(),
|
database_path: "./database.mochi".into(),
|
||||||
|
@ -94,29 +102,37 @@ impl Default for ServerSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
pub struct DurationSettings {
|
pub struct DurationSettings {
|
||||||
/// Maximum file lifetime, seconds
|
/// Maximum file lifetime, seconds
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub maximum: u32,
|
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
|
||||||
|
pub maximum: TimeDelta,
|
||||||
|
|
||||||
/// Default file lifetime, seconds
|
/// Default file lifetime, seconds
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub default: u32,
|
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
|
||||||
|
pub default: TimeDelta,
|
||||||
|
|
||||||
/// List of allowed durations. An empty list means any are allowed.
|
/// List of allowed durations. An empty list means any are allowed.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub allowed: Vec<u32>,
|
#[serde_as(as = "Vec<serde_with::DurationSeconds<i64>>")]
|
||||||
|
pub allowed: Vec<TimeDelta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DurationSettings {
|
impl Default for DurationSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
maximum: 259_200, // 72 hours
|
maximum: TimeDelta::days(3), // 72 hours
|
||||||
default: 21_600, // 6 hours
|
default: TimeDelta::hours(6), // 6 hours
|
||||||
// 1 hour, 6 hours, 24 hours, and 48 hours
|
// 1 hour, 6 hours, 24 hours, and 48 hours
|
||||||
allowed: vec![3600, 21_600, 86_400, 172_800],
|
allowed: vec![
|
||||||
|
TimeDelta::hours(1),
|
||||||
|
TimeDelta::hours(6),
|
||||||
|
TimeDelta::days(1),
|
||||||
|
TimeDelta::days(2),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,38 @@
|
||||||
@import url('https://g2games.dev/assets/fonts/fonts.css');
|
@import url('https://g2games.dev/assets/fonts/fonts.css');
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: black;
|
font-family: sans-serif;
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file_upload {
|
h1 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
display: block;
|
display: block;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
padding: 5px;
|
padding: 2px;
|
||||||
border: 1px solid grey;
|
border: 1px solid grey;
|
||||||
|
background-color: #EEE;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 10px;
|
margin: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: #CCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
#durationBox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: fit-content;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#durationBox > p {
|
||||||
|
font-size: 10pt;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
vertical-align: center;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ let progressBar;
|
||||||
let progressValue;
|
let progressValue;
|
||||||
let statusNotifier;
|
let statusNotifier;
|
||||||
let uploadedFilesDisplay;
|
let uploadedFilesDisplay;
|
||||||
|
let durationBox;
|
||||||
|
|
||||||
let uploadInProgress = false;
|
let uploadInProgress = false;
|
||||||
|
|
||||||
|
@ -9,11 +10,6 @@ const TOO_LARGE_TEXT = "File is too large!";
|
||||||
const ERROR_TEXT = "An error occured!";
|
const ERROR_TEXT = "An error occured!";
|
||||||
|
|
||||||
let CAPABILITIES;
|
let CAPABILITIES;
|
||||||
async function getServerCapabilities() {
|
|
||||||
CAPABILITIES = await fetch("info").then((response) => response.json());
|
|
||||||
console.log(CAPABILITIES);
|
|
||||||
}
|
|
||||||
getServerCapabilities();
|
|
||||||
|
|
||||||
async function formSubmit(form) {
|
async function formSubmit(form) {
|
||||||
if (uploadInProgress) {
|
if (uploadInProgress) {
|
||||||
|
@ -103,4 +99,34 @@ document.addEventListener("DOMContentLoaded", function(_event){
|
||||||
progressValue = document.getElementById("uploadProgressValue");
|
progressValue = document.getElementById("uploadProgressValue");
|
||||||
statusNotifier = document.getElementById("uploadStatus");
|
statusNotifier = document.getElementById("uploadStatus");
|
||||||
uploadedFilesDisplay = document.getElementById("uploadedFilesDisplay");
|
uploadedFilesDisplay = document.getElementById("uploadedFilesDisplay");
|
||||||
|
durationBox = document.getElementById("durationBox");
|
||||||
|
|
||||||
|
getServerCapabilities();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function toPrettyTime(seconds) {
|
||||||
|
var days = Math.floor(seconds / 86400);
|
||||||
|
var hours = Math.floor((seconds - (days * 86400)) / 3600);
|
||||||
|
var mins = Math.floor((seconds - (hours * 3600) - (days * 86400)) / 60);
|
||||||
|
var secs = seconds - (hours * 3600) - (mins * 60) - (days * 86400);
|
||||||
|
|
||||||
|
if(days == 0) {days = "";} else if(days == 1) {days += "<br>day"} else {days += "<br>days"}
|
||||||
|
if(hours == 0) {hours = "";} else if(hours == 1) {hours += "<br>hour"} else {hours += "<br>hours"}
|
||||||
|
if(mins == 0) {mins = "";} else if(mins == 1) {mins += "<br>minute"} else {mins += "<br>minutes"}
|
||||||
|
if(secs == 0) {secs = "";} else if(secs == 1) {secs += "<br>second"} else {secs += "<br>seconds"}
|
||||||
|
|
||||||
|
return (days + " " + hours + " " + mins + " " + secs).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getServerCapabilities() {
|
||||||
|
CAPABILITIES = await fetch("info").then((response) => response.json());
|
||||||
|
|
||||||
|
let file_duration = document.getElementById("fileDuration");
|
||||||
|
file_duration.value = CAPABILITIES.default_duration + "s";
|
||||||
|
|
||||||
|
for (duration in CAPABILITIES.allowed_durations) {
|
||||||
|
const durationOption = durationBox.appendChild(document.createElement("p"));
|
||||||
|
durationOption.innerHTML = toPrettyTime(CAPABILITIES.allowed_durations[duration]);
|
||||||
|
durationOption.classList.add("button");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::error::Error;
|
||||||
use chrono::TimeDelta;
|
use chrono::TimeDelta;
|
||||||
|
|
||||||
pub fn parse_time_string(string: &str) -> Result<TimeDelta, Box<dyn Error>> {
|
pub fn parse_time_string(string: &str) -> Result<TimeDelta, Box<dyn Error>> {
|
||||||
if string.len() > 5 {
|
if string.len() > 7 {
|
||||||
return Err("Not valid time string".into())
|
return Err("Not valid time string".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue