Compare commits

..

2 Commits

Author SHA1 Message Date
6421074931 added routes for listing days & getting days
/api/days?from=...&to=...
/api/day?day=...
2025-10-13 16:32:28 +02:00
a34dc18381 implemented load_day & list_day_in_timespan in IDStore 2025-10-13 16:31:15 +02:00
3 changed files with 73 additions and 18 deletions

View File

@@ -90,4 +90,23 @@ impl<T: Persistence> IDStore<T> {
} }
changed changed
} }
/// Load and return a AttendanceDay. Nothing more. Nothing less.
pub async fn load_day(&mut self, day: Day) -> Option<AttendanceDay> {
if day == self.current_day.date {
return Some(self.current_day.clone());
}
self.persistence_layer.load_day(day).await
}
pub async fn list_days_in_timespan(&mut self, from: Day, to: Day) -> Vec<Day> {
let all_days = self.persistence_layer.list_days().await;
all_days
.into_iter()
.filter(|e| *e >= from)
.filter(|e| *e <= to)
.collect()
}
} }

View File

@@ -1,11 +1,12 @@
use esp_println::dbg;
use picoserve::{ use picoserve::{
extract::{Json, State}, extract::{Json, Query, State},
response::{self, IntoResponse}, response::{self, IntoResponse},
}; };
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
store::{Name, tally_id::TallyID}, store::{self, Name, day::Day, tally_id::TallyID},
webserver::{app::AppState, sse::IDEvents}, webserver::{app::AppState, sse::IDEvents},
}; };
@@ -15,27 +16,25 @@ pub struct NewMapping {
name: Name, name: Name,
} }
// struct MappingWrapper(IDMapping); #[derive(Deserialize)]
// pub struct QueryTimespan {
// impl Serialize for MappingWrapper { from: u64,
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> to: u64,
// where }
// S: serde::Serializer,
// {
// use serde::ser::SerializeMap;
// let mut map = serializer.serialize_map(Some(self.0.id_map.len()))?;
// for (k, v) in &self.0.id_map {
// map.serialize_entry(tally_id_to_hex_string(*k).unwrap().as_str(), &v)?;
// }
// map.end()
// }
// }
#[derive(Deserialize)]
pub struct QueryDay {
timestamp: Option<u64>,
day: Option<u32>,
}
// GET /api/mapping
pub async fn get_mapping(State(state): State<AppState>) -> impl IntoResponse { pub async fn get_mapping(State(state): State<AppState>) -> impl IntoResponse {
let store = state.store.lock().await; let store = state.store.lock().await;
response::Json(store.mapping.clone()) response::Json(store.mapping.clone())
} }
// POST /api/mapping
pub async fn add_mapping( pub async fn add_mapping(
State(state): State<AppState>, State(state): State<AppState>,
Json(data): Json<NewMapping>, Json(data): Json<NewMapping>,
@@ -44,6 +43,41 @@ pub async fn add_mapping(
store.mapping.add_mapping(data.id, data.name); store.mapping.add_mapping(data.id, data.name);
} }
// SSE /api/idevent
pub async fn get_idevent(State(state): State<AppState>) -> impl IntoResponse { pub async fn get_idevent(State(state): State<AppState>) -> impl IntoResponse {
response::EventStream(IDEvents(state.chan.subscriber().unwrap())) response::EventStream(IDEvents(state.chan.subscriber().unwrap()))
} }
// GET /api/days
pub async fn get_days(
State(state): State<AppState>,
Query(QueryTimespan { from, to }): Query<QueryTimespan>,
) -> impl IntoResponse {
let from_day = Day::new_from_timestamp(from);
let to_day = Day::new_from_timestamp(to);
let mut store = state.store.lock().await;
let days = store.list_days_in_timespan(from_day, to_day).await;
response::Json(days)
}
// GET /api/day
pub async fn get_day(
State(state): State<AppState>,
Query(QueryDay { timestamp, day }): Query<QueryDay>,
) -> Result<impl IntoResponse, impl IntoResponse> {
let parsed_day = timestamp
.map(Day::new_from_timestamp)
.or_else(|| day.map(Day::new))
.ok_or((response::StatusCode::NOT_FOUND, "Not found"))?;
let mut store = state.store.lock().await;
match store.load_day(parsed_day).await {
Some(att_day) => Ok(response::Json(att_day)),
None => Err((response::StatusCode::NOT_FOUND, "Not found")),
}
}

View File

@@ -5,7 +5,7 @@ use picoserve::{AppWithStateBuilder, routing::get};
use crate::{ use crate::{
TallyChannel, UsedStore, TallyChannel, UsedStore,
webserver::{ webserver::{
api::{add_mapping, get_idevent, get_mapping}, api::{add_mapping, get_day, get_days, get_idevent, get_mapping},
assets::Assets, assets::Assets,
}, },
}; };
@@ -26,5 +26,7 @@ impl AppWithStateBuilder for AppProps {
picoserve::Router::from_service(Assets) picoserve::Router::from_service(Assets)
.route("/api/mapping", get(get_mapping).post(add_mapping)) .route("/api/mapping", get(get_mapping).post(add_mapping))
.route("/api/idevent", get(get_idevent)) .route("/api/idevent", get(get_idevent))
.route("/api/days", get(get_days))
.route("/api/day", get(get_day))
} }
} }