add first template of app

This commit is contained in:
Philipp Hofer 2025-04-06 15:13:12 +02:00
parent 8d40522242
commit 72fea73e44
10 changed files with 2305 additions and 37 deletions

2
.env Normal file
View File

@ -0,0 +1,2 @@
DATABASE_URL=sqlite://db.sqlite
PORT=3000

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

2163
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

14
Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "stationslauf"
version = "0.1.0"
edition = "2024"
[dependencies]
axum = "0.8"
dotenv = "0.15"
maud = { version = "0.27", features = ["axum"] }
serde = "1.0"
sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls", "macros"] }
tokio = { version = "1.44", features = ["macros", "rt-multi-thread"] }
tracing = "0.1"

View File

@ -1,45 +1,9 @@
# Stationslauf # Stationslauf
## Techstack ## Missing Techstack
- Rust + Axum as backend
- Maud as template engine
- sqlite as DB
- HTMX as frontend - HTMX as frontend
## DB Modell
- group
- id
- name
- 'pfadigruppe'
- notes
- amount_people
- first_station_id -> station
- station
- id
- name
- amount_people
- last_login
- pw (6-8 auto-generated chars, printed on qr code)
- lat/lng
- group_station
- group_id
- station_id
- points
- notes
- arrived_at
- started_at
- left_at
- path
- id
- name // e.g. 'wiwö'
- path_station // TODO: better name
- path_id
- station_id
- pos // arrange stations on the path, second order -> station_id?
## Fancy features ## Fancy features
- see when a group starts going to your direction - see when a group starts going to your direction
- QR codes for groups, stations can then scan it? - QR codes for groups, stations can then scan it?

BIN
db.sqlite Normal file

Binary file not shown.

46
migrations.sqlite Normal file
View File

@ -0,0 +1,46 @@
CREATE TABLE station (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
amount_people INTEGER,
last_login TIMESTAMP,
pw TEXT NOT NULL,
lat REAL,
lng REAL
);
CREATE TABLE "group" (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
pfadigruppe TEXT,
notes TEXT,
amount_people INTEGER,
first_station_id INTEGER,
FOREIGN KEY (first_station_id) REFERENCES station(id)
);
CREATE TABLE group_station (
group_id INTEGER,
station_id INTEGER,
points INTEGER,
notes TEXT,
arrived_at TIMESTAMP,
started_at TIMESTAMP,
left_at TIMESTAMP,
PRIMARY KEY (group_id, station_id),
FOREIGN KEY (group_id) REFERENCES "group"(id),
FOREIGN KEY (station_id) REFERENCES station(id)
);
CREATE TABLE path (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE path_station (
path_id INTEGER,
station_id INTEGER,
pos INTEGER,
PRIMARY KEY (path_id, station_id),
FOREIGN KEY (path_id) REFERENCES path(id),
FOREIGN KEY (station_id) REFERENCES station(id)
);

15
src/lib.rs Normal file
View File

@ -0,0 +1,15 @@
use axum::Router;
use sqlx::SqlitePool;
use std::sync::Arc;
use tokio::net::TcpListener;
mod station;
/// Starts the main application.
pub async fn start(listener: TcpListener, db: SqlitePool) {
let app = Router::new()
.nest("/station", station::routes())
.with_state(Arc::new(db));
axum::serve(listener, app).await.unwrap();
}

20
src/main.rs Normal file
View File

@ -0,0 +1,20 @@
use dotenv::dotenv;
use sqlx::{pool::PoolOptions, SqlitePool};
use std::env;
#[tokio::main]
async fn main() {
dotenv().ok(); // load .env variables
// DB
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let db: SqlitePool = PoolOptions::new().connect(&database_url).await.unwrap();
// Axum
let port = env::var("PORT").expect("PORT must be set");
let listener = tokio::net::TcpListener::bind(&format!("0.0.0.0:{port}"))
.await
.unwrap();
stationslauf::start(listener, db).await;
}

43
src/station.rs Normal file
View File

@ -0,0 +1,43 @@
use axum::{extract::State, routing::get, Router};
use maud::{html, Markup};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool};
use std::sync::Arc;
#[derive(FromRow, Debug, Serialize, Deserialize)]
struct Station {
id: u64,
name: String,
amount_people: u8,
last_login: Option<String>, // TODO use proper timestamp (NaiveDateTime?)
pw: String,
lat: Option<f64>,
lng: Option<f64>,
}
impl Station {
async fn all(db: &SqlitePool) -> Vec<Self> {
sqlx::query_as::<_, Self>(
"SELECT id, name, amount_people, last_login, pw, lat, lng FROM station;",
)
.fetch_all(db)
.await
.unwrap()
}
}
async fn get_stations(State(db): State<Arc<SqlitePool>>) -> Markup {
let all = Station::all(&db).await;
let mut ret = String::new();
for a in all {
ret.push_str(&a.name);
}
html! {
div { (ret) }
}
}
pub(super) fn routes() -> Router<Arc<SqlitePool>> {
Router::new().route("/", get(get_stations))
}