pub mod stats; use crate::auth::Authorized; use crate::database::latest::trees::{category, session}; use crate::status_json::StatusJson; use bincode::{deserialize, serialize}; use rocket::http::Status; use rocket::{get, State}; use rocket_contrib::templates::Template; use rocket_contrib::uuid::Uuid; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashMap}; use std::time::Duration; #[get("/")] pub fn index(_auth: Authorized, db: State<'_, sled::Db>) -> Result { #[derive(Debug, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq)] struct Node { category: category::V, children: BTreeMap, } #[derive(Debug, Serialize, Deserialize)] struct TemplateContext { categories: BTreeMap, } let categories_tree = db.open_tree(category::NAME)?; let mut categories = category::get_all(&categories_tree)?; // filter archived categories categories.retain(|_, category| !category.deleted); // collect the top-level categories (those without a parent) let mut top_level_nodes: BTreeMap = categories .iter() .filter(|(_, c)| c.parent.is_none()) .map(|(&id, category)| { let node = Node { category: category.clone(), children: Default::default(), }; (id, node) }) .collect(); // remove top-level categories from the list for id in top_level_nodes.keys() { categories.remove(id); } /// populate `node.children with entries from `remaining` fn populate_node( node_id: category::K, node: &mut Node, remaining: &mut HashMap, ) { // make a list of the nodes children let mut new_children = vec![]; for (&id, category) in remaining.iter() { if category.parent == Some(node_id) { new_children.push(id); } } // move the children from `remaining` to `node.children` for &id in &new_children { let child_node = Node { category: remaining.remove(&id).unwrap(), children: Default::default(), }; node.children.insert(id, child_node); } // recursively populate the childrens children for (child_id, child) in node.children.iter_mut() { populate_node(*child_id, child, remaining); } } for (id, node) in top_level_nodes.iter_mut() { populate_node(*id, node, &mut categories); } let context = TemplateContext { categories: top_level_nodes, }; Ok(Template::render("index", &context)) } #[get("/session//edit")] pub fn session_edit( _auth: Authorized, session_uuid: Uuid, db: State<'_, sled::Db>, ) -> Result { #[derive(Debug, Serialize, Deserialize)] struct SessionPageContext { session: session::V, session_id: uuid::Uuid, } let session_uuid_s = sled::IVec::from(serialize(&session_uuid.into_inner())?); let sessions_tree = db.open_tree(session::NAME)?; match sessions_tree.get(session_uuid_s)? { None => Err(Status::NotFound.into()), Some(data) => { let context = SessionPageContext { session: deserialize(&data).unwrap(), session_id: session_uuid.into_inner(), }; Ok(Template::render("edit_session", &context)) } } } #[get("/history")] pub fn history(_auth: Authorized, db: State<'_, sled::Db>) -> Result { #[derive(Debug, Serialize, Deserialize)] struct HistoryEntryContext { category: category::V, session: session::V, session_id: uuid::Uuid, duration: Duration, } #[derive(Debug, Serialize, Deserialize)] struct TemplateContext { entries: Vec, } let categories_tree = db.open_tree(category::NAME)?; let sessions_tree = db.open_tree(session::NAME)?; let categories: HashMap = categories_tree .iter() .map(|result| { result.map(|(k, v)| deserialize(&k).and_then(|k| deserialize(&v).map(|v| (k, v)))) }) .collect::, _>>()??; let sessions: HashMap = sessions_tree .iter() .map(|result| { result.map(|(k, v)| deserialize(&k).and_then(|k| deserialize(&v).map(|v| (k, v)))) }) .collect::, _>>()??; let mut context = TemplateContext { entries: sessions .into_iter() .map(|(session_id, session)| HistoryEntryContext { duration: (session.ended - session.started).to_std().unwrap(), category: categories.get(&session.category).unwrap().clone(), session, session_id, }) .collect(), }; // Newest entries first context.entries.sort_by_key(|entry| entry.session.started); context.entries.reverse(); Ok(Template::render("history", &context)) }