add first template of app
This commit is contained in:
parent
8d40522242
commit
72fea73e44
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
2163
Cargo.lock
generated
Normal file
2163
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
Normal file
14
Cargo.toml
Normal 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"
|
||||
|
38
README.md
38
README.md
@ -1,45 +1,9 @@
|
||||
# Stationslauf
|
||||
|
||||
## Techstack
|
||||
## Missing Techstack
|
||||
|
||||
- Rust + Axum as backend
|
||||
- Maud as template engine
|
||||
- sqlite as DB
|
||||
- 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
|
||||
- see when a group starts going to your direction
|
||||
- QR codes for groups, stations can then scan it?
|
||||
|
46
migrations.sqlite
Normal file
46
migrations.sqlite
Normal 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
15
src/lib.rs
Normal 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
20
src/main.rs
Normal 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
43
src/station.rs
Normal 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))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user