Adds index.html

This commit is contained in:
2025-10-07 17:15:40 +02:00
parent 7f1af014ae
commit 8e8a51c3a0
4 changed files with 162 additions and 10 deletions

View File

@@ -78,7 +78,7 @@ pub async fn get(id: &str, meta: ReqMeta, state: &State<AppState>) -> Result<Nam
} }
} }
NamedFile::open(Path::new(state.image_path.as_str())) NamedFile::open(Path::new(state.static_dir.as_str()).join("image.png"))
.await .await
.map_err(|_| Status::InternalServerError) .map_err(|_| Status::InternalServerError)
} }

View File

@@ -7,21 +7,26 @@ mod schema;
use crate::api::hit; use crate::api::hit;
use crate::api::image; use crate::api::image;
use crate::api::tracker; use crate::api::tracker;
use crate::models::AppState;
use chrono::Local; use chrono::Local;
use diesel::{Connection, PgConnection}; use diesel::{Connection, PgConnection};
use rocket::State;
use rocket::fs::NamedFile;
use rocket::http::Status;
use std::env; use std::env;
use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
#[get("/")] #[get("/")]
fn index() -> &'static str { async fn index(state: &State<AppState>) -> Result<NamedFile, Status> {
"Hello world!" NamedFile::open(Path::new(state.static_dir.as_str()).join("index.html"))
.await
.map_err(|_| Status::InternalServerError)
} }
// TODO: add auth
fn setup_logging() -> Result<(), fern::InitError> { fn setup_logging() -> Result<(), fern::InitError> {
let level_raw = env::var("LOG_LEVEL").unwrap_or("INFO".to_string()); let level_raw = env::var("LOG_LEVEL").unwrap_or("INFO".to_string());
let level = log::LevelFilter::from_str(&level_raw).expect("LOG_LEVEL invalid"); let level = log::LevelFilter::from_str(&level_raw).expect("LOG_LEVEL invalid");
@@ -49,11 +54,11 @@ fn rocket() -> _ {
setup_logging().expect("Failed to setup logging"); setup_logging().expect("Failed to setup logging");
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let image_path = env::var("IMAGE_PATH").expect("IMAGE_PATH must be set"); let static_dir = env::var("STATIC_DIR").expect("STATIC_DIR must be set");
let db = PgConnection::establish(&database_url) let db = PgConnection::establish(&database_url)
.expect(&format!("Error connecting to {}", database_url)); .expect(&format!("Error connecting to {}", database_url));
let app_data = models::AppState::new(db, image_path); let app_data = AppState::new(db, static_dir);
rocket::build() rocket::build()
.manage(app_data) .manage(app_data)
.mount("/", routes![index]) .mount("/", routes![index])

View File

@@ -6,14 +6,14 @@ pub mod tracker;
pub struct AppState { pub struct AppState {
pub db: Arc<Mutex<PgConnection>>, pub db: Arc<Mutex<PgConnection>>,
pub image_path: String, pub static_dir: String,
} }
impl AppState { impl AppState {
pub fn new(db: PgConnection, image_path: String) -> Self { pub fn new(db: PgConnection, static_dir: String) -> Self {
AppState { AppState {
db: Arc::new(Mutex::new(db)), db: Arc::new(Mutex::new(db)),
image_path, static_dir,
} }
} }
} }

147
static/index.html Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="author" content="Daniel Svitan">
<title>Setra</title>
<style>
body {
display: flex;
align-items: center;
flex-direction: column;
}
.container {
width: 60vw;
margin-top: 2rem;
}
h1 {
margin: 0;
}
p {
width: min-content;
}
.create-form {
display: flex;
flex-direction: column;
border: 1px black solid;
padding: 0.5rem;
border-radius: 0.5rem;
}
.create-form label {
font-size: 1.15rem;
}
.create-form input {
width: min-content;
border-radius: 0.5rem;
border: 1px gray solid;
padding: 0.4rem 0.4rem 0.15rem 0.4rem;
font-size: 1.05rem;
}
.create-form button[type=submit] {
width: min-content;
margin-top: 0.5rem;
border: none;
font-size: 1.05rem;
color: #eeeeee;
background: #0078e7;
padding: 0.5rem 0.75rem 0.25rem 0.75rem;
border-radius: 0.5rem;
cursor: pointer;
}
.dialog {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
backdrop-filter: blur(1rem);
}
.dialog form {
border: 1px solid black;
padding: 0.5rem;
border-radius: 0.5rem;
display: flex;
flex-direction: column;
}
.dialog form label {
font-size: 1.15rem;
}
.dialog form input {
width: min-content;
border-radius: 0.5rem;
border: 1px gray solid;
padding: 0.4rem 0.4rem 0.15rem 0.4rem;
font-size: 1.05rem;
}
.dialog form button[type=submit] {
width: min-content;
margin-top: 0.5rem;
border: none;
font-size: 1.05rem;
color: #eeeeee;
background: #0078e7;
padding: 0.5rem 0.75rem 0.25rem 0.75rem;
border-radius: 0.5rem;
align-self: end;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<h1>Setra</h1>
<form class="create-form">
<label for="name-input">Name:</label>
<input id="name-input" type="text">
<button type="submit">Create</button>
</form>
<div class="dialog" id="dialog">
<form onsubmit="saveAPIKey(event)">
<label for="api-key-input">API key:</label>
<input id="api-key-input" type="password">
<button type="submit">Save</button>
</form>
</div>
</div>
<script>
function saveAPIKey(event) {
event.preventDefault();
const input = document.getElementById("api-key-input");
localStorage.setItem("api-key", input.value);
console.log("set api-key to", input.value);
document.getElementById("dialog").style.display = "none";
}
function init() {
if (localStorage.getItem("api-key")) {
document.getElementById("dialog").style.display = "none";
}
}
init();
</script>
</body>
</html>