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
|
# 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?
|
||||||
|
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