156 lines
4.1 KiB
Rust
156 lines
4.1 KiB
Rust
mod api;
|
|
mod axum_ructe;
|
|
|
|
use axum_ructe::render;
|
|
|
|
use cm_lib::{
|
|
models::{Drink, Shift},
|
|
report::GenerateDrinkReport,
|
|
schema::shifts,
|
|
};
|
|
|
|
use axum::{
|
|
extract::{Path, State},
|
|
response::IntoResponse,
|
|
routing::get,
|
|
Router,
|
|
};
|
|
|
|
use diesel::{
|
|
result::OptionalExtension, BelongingToDsl, ExpressionMethods, QueryDsl, SelectableHelper,
|
|
};
|
|
|
|
use diesel_async::{
|
|
pooled_connection::{deadpool::Pool, AsyncDieselConnectionManager},
|
|
AsyncMysqlConnection, RunQueryDsl,
|
|
};
|
|
|
|
use dotenvy::dotenv;
|
|
use std::net::SocketAddr;
|
|
use tower_http::services::{ServeDir, ServeFile};
|
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
|
|
|
use crate::templates::*;
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
|
|
|
fn establish_connection() -> Pool<AsyncMysqlConnection> {
|
|
dotenv().ok();
|
|
|
|
let database_url = std::env::var("DATABASE_URL").expect("You must set DATABASE_URL");
|
|
let config = AsyncDieselConnectionManager::<AsyncMysqlConnection>::new(database_url);
|
|
|
|
Pool::builder(config)
|
|
.build()
|
|
.expect("Error making connection pool")
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
enum AdaUpdate {
|
|
RefreshDancers,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct AppState {
|
|
connection: Pool<AsyncMysqlConnection>,
|
|
ada_sender: tokio::sync::broadcast::Sender<AdaUpdate>,
|
|
}
|
|
|
|
impl AppState {
|
|
fn init() -> Self {
|
|
Self {
|
|
connection: establish_connection(),
|
|
ada_sender: tokio::sync::broadcast::channel(10).0,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// initialize tracing
|
|
tracing_subscriber::registry()
|
|
.with(
|
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| "clubmanager=debug,tower_http=debug".into()),
|
|
)
|
|
.with(tracing_subscriber::fmt::layer())
|
|
.init();
|
|
|
|
let state = AppState::init();
|
|
|
|
let fallback_handler = ServeDir::new("dist").not_found_service(ServeFile::new("dist/404.html"));
|
|
|
|
// build our application with a route
|
|
let app = Router::new()
|
|
.nest("/api", api::router())
|
|
.route("/", get(root))
|
|
.route("/ada", get(ada))
|
|
.route("/shift_reports", get(shift_reports))
|
|
.route("/shifts/:id/drinks", get(drinks))
|
|
.route("/shifts/:id/report", get(shift_report))
|
|
.fallback_service(fallback_handler)
|
|
.with_state(state);
|
|
|
|
// run our app with hyper
|
|
// `axum::Server` is a re-export of `hyper::Server`
|
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
|
tracing::debug!("listening on http://{}/", addr);
|
|
axum::Server::bind(&addr)
|
|
.serve(app.into_make_service())
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
async fn root(State(state): State<AppState>) -> impl IntoResponse {
|
|
let mut conn = state.connection.get().await.unwrap();
|
|
|
|
let open_shift: Option<Shift> = {
|
|
use cm_lib::schema::shifts::dsl::*;
|
|
|
|
shifts
|
|
.filter(end.is_null())
|
|
.select(Shift::as_select())
|
|
.first(&mut conn)
|
|
.await
|
|
.optional()
|
|
.expect("Query failed: No open shifts found")
|
|
};
|
|
|
|
tracing::debug!("{open_shift:?}");
|
|
|
|
render!(templates::home_html, open_shift)
|
|
}
|
|
|
|
async fn drinks(Path(id): Path<u32>) -> impl IntoResponse {
|
|
render!(templates::drinks_html, id)
|
|
}
|
|
|
|
async fn shift_report(State(state): State<AppState>, Path(id): Path<u32>) -> impl IntoResponse {
|
|
let mut conn = state.connection.get().await.unwrap();
|
|
let shift: Shift = shifts::table.find(id).first(&mut conn).await.unwrap();
|
|
let drinks: Vec<Drink> = Drink::belonging_to(&shift).load(&mut conn).await.unwrap();
|
|
|
|
render!(
|
|
crate::templates::shift_report_html,
|
|
drinks.generate_report()
|
|
)
|
|
}
|
|
|
|
async fn shift_reports(State(state): State<AppState>) -> impl IntoResponse {
|
|
let mut conn = state.connection.get().await.unwrap();
|
|
|
|
let mut shifts: Vec<Shift> = shifts::table
|
|
.select(Shift::as_select())
|
|
.load(&mut conn)
|
|
.await
|
|
.unwrap();
|
|
|
|
shifts.sort_by(|a, b| b.start.cmp(&a.start));
|
|
|
|
render!(shift_reports_html, shifts)
|
|
}
|
|
|
|
async fn ada() -> impl IntoResponse {
|
|
render!(ada_html)
|
|
}
|