From 4b07ba4c462fb4bb1570237853b6f49ca7686b8b Mon Sep 17 00:00:00 2001
From: G2-Games <ke0bhogsg@gmail.com>
Date: Mon, 28 Oct 2024 00:39:10 -0500
Subject: [PATCH] Clean up code in various ways

---
 src/database.rs  | 12 ++++++-----
 src/endpoints.rs |  5 ++---
 src/main.rs      | 44 ++++++++++------------------------------
 src/pages.rs     | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
 web/main.css     |  9 +++++++--
 web/request.js   |  2 +-
 6 files changed, 79 insertions(+), 45 deletions(-)
 create mode 100644 src/pages.rs

diff --git a/src/database.rs b/src/database.rs
index 968903f..c3f90dd 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -69,19 +69,19 @@ impl Database {
     /// Insert a [`MochiFile`] into the database.
     ///
     /// If the database already contained this value, then `false` is returned.
-    pub fn insert(&mut self, entry: MochiFile) -> bool {
+    pub fn insert(&mut self, mmid: &Mmid, entry: MochiFile) -> bool {
         if let Some(s) = self.hashes.get_mut(&entry.hash) {
             // If the database already contains the hash, make sure the file is unique
-            if !s.insert(entry.mmid.clone()) {
+            if !s.insert(mmid.clone()) {
                 return false;
             }
         } else {
             // If the database does not contain the hash, create a new set for it
             self.hashes
-                .insert(entry.hash, HashSet::from([entry.mmid.clone()]));
+                .insert(entry.hash, HashSet::from([mmid.clone()]));
         }
 
-        self.entries.insert(entry.mmid.clone(), entry.clone());
+        self.entries.insert(mmid.clone(), entry.clone());
 
         true
     }
@@ -266,7 +266,9 @@ pub async fn clean_loop(
 
 /// A unique identifier for an entry in the database, 8 characters long,
 /// consists of ASCII alphanumeric characters (`a-z`, `A-Z`, and `0-9`).
-#[derive(Debug, PartialEq, Eq, Clone, Decode, Encode, Hash, Deserialize, Serialize)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+#[derive(Decode, Encode)]
+#[derive(Deserialize, Serialize)]
 pub struct Mmid(String);
 
 impl Mmid {
diff --git a/src/endpoints.rs b/src/endpoints.rs
index 8133422..cf2fdab 100644
--- a/src/endpoints.rs
+++ b/src/endpoints.rs
@@ -54,10 +54,9 @@ pub async fn lookup_mmid(db: &State<Arc<RwLock<Database>>>, mmid: &str) -> Optio
     ))))
 }
 
-/// Look up the [`Mmid`] of a file to find it.
+/// Look up the [`Mmid`] of a file to find it, along with the name of the file
 #[get("/f/<mmid>/<name>")]
-pub async fn lookup_mmid_name(
-    db: &State<Arc<RwLock<Database>>>,
+pub async fn lookup_mmid_name(db: &State<Arc<RwLock<Database>>>,
     settings: &State<Settings>,
     mmid: &str,
     name: &str,
diff --git a/src/main.rs b/src/main.rs
index ef1af86..eedc050 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ mod endpoints;
 mod settings;
 mod strings;
 mod utils;
+mod pages;
 
 use std::{
     fs,
@@ -13,37 +14,16 @@ use chrono::{DateTime, TimeDelta, Utc};
 use database::{clean_loop, Database, Mmid, MochiFile};
 use endpoints::{lookup_mmid, lookup_mmid_name, server_info};
 use log::info;
-use maud::{html, Markup, PreEscaped, DOCTYPE};
+use maud::{html, Markup, PreEscaped};
+use pages::{api_info, footer, head};
 use rocket::{
-    data::{Limits, ToByteUnit},
-    form::Form,
-    fs::{FileServer, Options, TempFile},
-    get,
-    http::ContentType,
-    post,
-    response::content::{RawCss, RawJavaScript},
-    routes,
-    serde::{json::Json, Serialize},
-    tokio, Config, FromForm, State,
+    data::{Limits, ToByteUnit}, form::Form, fs::{FileServer, Options, TempFile}, get, http::ContentType, post, response::content::{RawCss, RawJavaScript}, routes, serde::{json::Json, Serialize}, tokio, Config, FromForm, State
 };
 use settings::Settings;
 use strings::{parse_time_string, to_pretty_time};
 use utils::hash_file;
 use uuid::Uuid;
 
-fn head(page_title: &str) -> Markup {
-    html! {
-        (DOCTYPE)
-        meta charset="UTF-8";
-        meta name="viewport" content="width=device-width, initial-scale=1";
-        title { (page_title) }
-        // Javascript stuff for client side handling
-        script src="./request.js" { }
-        link rel="icon" type="image/svg+xml" href="favicon.svg";
-        link rel="stylesheet" href="./main.css";
-    }
-}
-
 /// Stylesheet
 #[get("/main.css")]
 fn stylesheet() -> RawCss<&'static str> {
@@ -65,6 +45,7 @@ fn favicon() -> (ContentType, &'static str) {
 fn home(settings: &State<Settings>) -> Markup {
     html! {
         (head("Confetti-Box"))
+        script src="./request.js" { }
 
         center {
             h1 { "Confetti-Box 🎉" }
@@ -86,10 +67,10 @@ fn home(settings: &State<Settings>) -> Markup {
             }
             form #uploadForm {
                 // It's stupid how these can't be styled so they're just hidden here...
-                input #fileInput type="file" name="fileUpload" multiple
-                    onchange="formSubmit(this.parentNode)" data-max-filesize=(settings.max_filesize) style="display:none;";
                 input #fileDuration type="text" name="duration" minlength="2"
                     maxlength="7" value=(settings.duration.default.num_seconds().to_string() + "s") style="display:none;";
+                input #fileInput type="file" name="fileUpload" multiple
+                    onchange="formSubmit(this.parentNode)" data-max-filesize=(settings.max_filesize) style="display:none;";
             }
             hr;
 
@@ -99,13 +80,7 @@ fn home(settings: &State<Settings>) -> Markup {
             }
 
             hr;
-            footer {
-                p {a href="https://github.com/G2-Games/confetti-box" {"Source"}}
-                p {a href="https://g2games.dev/" {"My Website"}}
-                p {a href="api" {"API Info"}}
-                p {a href="#" {"Go"}}
-                p {a href="#" {"Here"}}
-            }
+            (footer())
         }
     }
 }
@@ -171,7 +146,7 @@ async fn handle_upload(
     // Move it to the new proper place
     std::fs::rename(temp_filename, settings.file_dir.join(file_hash.to_string()))?;
 
-    db.write().unwrap().insert(constructed_file.clone());
+    db.write().unwrap().insert(&file_mmid, constructed_file.clone());
     db.write().unwrap().save();
 
     Ok(Json(ClientResponse {
@@ -253,6 +228,7 @@ async fn main() {
             config.server.root_path.clone() + "/",
             routes![
                 home,
+                api_info,
                 handle_upload,
                 form_handler_js,
                 stylesheet,
diff --git a/src/pages.rs b/src/pages.rs
new file mode 100644
index 0000000..87c6d5a
--- /dev/null
+++ b/src/pages.rs
@@ -0,0 +1,52 @@
+use maud::{html, Markup, DOCTYPE};
+use rocket::get;
+
+pub fn head(page_title: &str) -> Markup {
+    html! {
+        (DOCTYPE)
+        meta charset="UTF-8";
+        meta name="viewport" content="width=device-width, initial-scale=1";
+        title { (page_title) }
+        link rel="icon" type="image/svg+xml" href="favicon.svg";
+        link rel="stylesheet" href="./main.css";
+    }
+}
+
+pub fn footer() -> Markup {
+    html! {
+        footer {
+            p {a href="/" {"Home"}}
+            p {a href="https://github.com/G2-Games/confetti-box" {"Source"}}
+            p {a href="https://g2games.dev/" {"My Website"}}
+            p {a href="api_info" {"API Info"}}
+            p {a href="https://ko-fi.com/g2_games" {"Donate"}}
+        }
+    }
+}
+
+#[get("/api_info")]
+pub fn api_info() -> Markup {
+    html! {
+        (head("Confetti-Box | API"))
+
+        center {
+            h1 { "API Information" }
+            hr;
+
+            div style="text-align: left;" {
+                p {
+                    """
+                    The API for this service can be used by POST ing a form
+                    with an expiration time and file to upload to the upload
+                    endpoint:
+                    """
+                }
+                pre { "/upload POST duration=\"6h\" fileUpload=(file data)" }
+
+            }
+
+            hr;
+            (footer())
+        }
+    }
+}
diff --git a/web/main.css b/web/main.css
index d362099..3e41a99 100644
--- a/web/main.css
+++ b/web/main.css
@@ -1,5 +1,3 @@
-@import url('https://g2games.dev/assets/fonts/fonts.css');
-
 body {
     font-family: sans-serif;
 }
@@ -74,6 +72,13 @@ button.main_file_upload {
     border: 2px dashed grey;
 }
 
+pre {
+    color: white;
+    background-color: black;
+    font-size: 11pt;
+    padding: 10px;
+}
+
 #durationBox {
     margin-top: 0;
     display: flex;
diff --git a/web/request.js b/web/request.js
index 5619fd5..32a47e9 100644
--- a/web/request.js
+++ b/web/request.js
@@ -72,8 +72,8 @@ async function fileSend(files, duration, maxSize) {
         // Create and send FormData
         try {
             const formData = new FormData();
-            formData.append("fileUpload", file);
             formData.append("duration", duration);
+            formData.append("fileUpload", file);
             request.send(formData);
         } catch (e) {
             makeErrored(progressBar, progressText, linkRow, ERROR_TEXT);