use std::sync::Arc;
use axum::{
extract::State,
response::Html,
response::IntoResponse,
routing::{get, post},
Form, Router,
};
use minijinja::context;
use serde::{Deserialize, Serialize};
use crate::{
client::corpora,
state::{GlobalAppState, Session, SessionArg},
Result,
};
pub fn create_routes() -> Result<Router<Arc<GlobalAppState>>> {
let result = Router::new().route("/", get(show)).route("/", post(update));
Ok(result)
}
#[derive(Serialize)]
struct Corpus {
name: String,
selected: bool,
}
async fn show(
session: Session,
State(app_state): State<Arc<GlobalAppState>>,
) -> Result<impl IntoResponse> {
let selected_corpora = &session.selected_corpora();
let corpora: Vec<_> = corpora::list(&SessionArg::Session(session.clone()), app_state.as_ref())
.await?
.into_iter()
.map(|name| Corpus {
selected: selected_corpora.contains(&name),
name,
})
.collect();
let html = app_state
.templates
.get_template("corpora.html")?
.render(context! {
corpora,
session => session,
filter => "",
})?;
Ok(Html(html))
}
#[derive(Deserialize, Debug)]
struct Params {
filter: String,
add_corpus: Option<String>,
remove_corpus: Option<String>,
add_all_corpora: Option<String>,
clear_selection: Option<String>,
}
async fn update(
mut session: Session,
State(app_state): State<Arc<GlobalAppState>>,
Form(payload): Form<Params>,
) -> Result<impl IntoResponse> {
let corpora = corpora::list(&SessionArg::Session(session.clone()), app_state.as_ref()).await?;
let mut filtered_corpora: Vec<_> = corpora
.iter()
.filter(|c| c.to_lowercase().contains(&payload.filter.to_lowercase()))
.cloned()
.collect();
filtered_corpora.sort_by_key(|k| k.to_lowercase());
let mut selected_corpora = session.selected_corpora().clone();
if let Some(add_corpus) = payload.add_corpus {
selected_corpora.insert(add_corpus);
}
if let Some(remove_corpus) = payload.remove_corpus {
selected_corpora.remove(&remove_corpus);
}
if payload.add_all_corpora == Some("true".to_string()) {
for c in &filtered_corpora {
selected_corpora.insert(c.clone());
}
}
if payload.clear_selection == Some("true".to_string()) {
selected_corpora.clear();
}
session.set_selected_corpora(selected_corpora)?;
let corpora: Vec<Corpus> = filtered_corpora
.into_iter()
.map(|name| Corpus {
selected: session.selected_corpora().contains(&name),
name,
})
.collect();
let html = app_state
.templates
.get_template("corpora.html")?
.render(context! {
corpora,
filter => payload.filter,
session => session,
})?;
Ok(Html(html))
}
#[cfg(test)]
mod tests;