use axum::{ Router, extract::{Path, Query, State}, http::StatusCode, response::{Html, Redirect, Result}, routing::{get, post}, }; use minijinja::context; use serde::Serialize; use serde_qs::web::QsForm; use wallsocket_core::{ Database, schema::{CompletedSchema, Schema}, }; use wallsocket_input::{Id, PendingInputRequest}; use crate::{AppState, helpers::Pagination}; use std::{ops::Deref, str::FromStr, sync::Arc}; pub fn router + Send + Sync + 'static>() -> Router>> { Router::new() .route("/input", get(pending_input::)) .route("/input/{id}/submit", post(submit_input::)) } #[derive(Debug, Clone, Serialize)] struct PendingInput { id: String, request: Schema, } async fn pending_input + Send + Sync + 'static>( page: Query, State(state): State>>, ) -> Result> { let after = if let Some(after) = &page.after { Some(Id::from_str(after).map_err(|e| { ( StatusCode::BAD_REQUEST, format!("error parsing `after`: {e}"), ) })?) } else { None }; let results: Vec<_> = state .config .input_registry .pending() .await .iter() .skip_while(|p| { if let Some(after) = after { p.id <= after } else { false // don't skip anything, ie start at the beginning } }) .take(page.limit) .map(PendingInput::from) .collect(); Ok(Html( state .templates .get_template("pending_inputs") .unwrap() .render(context! { results }) .unwrap(), )) } impl From<&PendingInputRequest> for PendingInput { fn from(value: &PendingInputRequest) -> Self { Self { id: value.id.to_string(), request: value.request.clone(), } } } async fn submit_input + Send + Sync + 'static>( State(state): State>>, Path(id): Path, QsForm(body): QsForm, ) -> Result { state .config .input_registry .answer( Id::from_str(&id) .map_err(|e| (StatusCode::BAD_REQUEST, format!("error parsing `id`: {e}")))?, body, ) .await .map_err(|e| { ( StatusCode::BAD_REQUEST, format!("error answering input request: {e}"), ) })?; Ok(Redirect::to("/input")) }