diff --git a/src/database/mod.rs b/src/database/mod.rs index f3e2bde..2678305 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,2 +1,5 @@ pub mod unversioned; pub mod v1; + +pub const SCHEMA_VERSION: unversioned::global::schema_version::V = 1; +pub use self::v1 as latest; diff --git a/src/database/unversioned.rs b/src/database/unversioned.rs index edf4205..0acd674 100644 --- a/src/database/unversioned.rs +++ b/src/database/unversioned.rs @@ -1,6 +1,6 @@ pub mod global { pub mod schema_version { pub const K: &str = "SCHEMA_VERSION"; - pub type V = (u32, u32, u32); + pub type V = u32; } } diff --git a/src/database/v1.rs b/src/database/v1.rs index 4416d21..abb0e00 100644 --- a/src/database/v1.rs +++ b/src/database/v1.rs @@ -35,8 +35,13 @@ pub mod trees { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct V { + /// The UUID of the category to which this session belongs pub category: trees::categories::K, + + /// The time when this session was started pub started: NaiveDateTime, + + /// The time when this session was ended pub ended: NaiveDateTime, } } diff --git a/src/main.rs b/src/main.rs index 688e0a6..f0bf41c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ mod handlebars_util; mod routes; mod status_json; +use bincode::{deserialize, serialize}; +use database::{unversioned::global::schema_version, SCHEMA_VERSION}; use dotenv::dotenv; use rocket_contrib::serve::StaticFiles; use rocket_contrib::templates::Template; @@ -15,6 +17,21 @@ fn main() -> io::Result<()> { let db_path = env::var("DB_PATH").expect("DB_PATH not set"); let sled = sled::open(db_path)?; + match sled.insert( + serialize(schema_version::K).unwrap(), + serialize(&SCHEMA_VERSION).unwrap(), + )? { + Some(prev_schema_version) => { + let prev_schema_version: schema_version::V = deserialize(&prev_schema_version).unwrap(); + println!( + "Schema version: {}, previously: {}", + SCHEMA_VERSION, prev_schema_version + ); + } + None => { + println!("Schema version: {}, previously: None", SCHEMA_VERSION); + } + } let rocket = rocket::ignite() .attach(Template::custom(|engines| { @@ -28,8 +45,9 @@ fn main() -> io::Result<()> { routes::pages::index, routes::pages::history, routes::api::create_category, - routes::api::activate_category, - routes::api::deactivate_category, + routes::api::start_session, + routes::api::end_session, + routes::api::delete_session, ], ); diff --git a/src/routes/api.rs b/src/routes/api.rs index e60b454..98d765d 100644 --- a/src/routes/api.rs +++ b/src/routes/api.rs @@ -1,10 +1,12 @@ -use crate::database::v1::trees::{categories, past_sessions}; +use crate::database::latest::trees::{categories, past_sessions}; +use crate::routes::pages; use crate::status_json::StatusJson; use bincode::{deserialize, serialize}; use chrono::{Duration, Utc}; use rocket::http::Status; use rocket::request::{Form, FromForm}; -use rocket::{post, State}; +use rocket::response::Redirect; +use rocket::{post, uri, State}; use sled::Transactional; use uuid::Uuid; @@ -34,23 +36,23 @@ pub fn create_category( Ok(Status::Ok.into()) } -#[post("/set_category//active")] -pub fn activate_category( +#[post("/category//start_session")] +pub fn start_session( category_uuid: String, db: State<'_, sled::Db>, ) -> Result { - toggle_category(category_uuid, true, db) + toggle_category_session(category_uuid, true, db) } -#[post("/set_category//inactive")] -pub fn deactivate_category( +#[post("/category//end_session")] +pub fn end_session( category_uuid: String, db: State<'_, sled::Db>, ) -> Result { - toggle_category(category_uuid, false, db) + toggle_category_session(category_uuid, false, db) } -pub fn toggle_category( +pub fn toggle_category_session( category_uuid: String, set_active: bool, db: State<'_, sled::Db>, @@ -101,3 +103,30 @@ pub fn toggle_category( }, )??) } + +#[post("/session//delete")] +pub fn delete_session( + session_uuid: String, + db: State<'_, sled::Db>, +) -> Result { + let session_uuid = Uuid::parse_str(&session_uuid)?; + let session_uuid_s = sled::IVec::from(serialize(&session_uuid)?); + + let past_sessions_tree = db.open_tree(past_sessions::NAME)?; + + match past_sessions_tree.remove(session_uuid_s)? { + Some(_) => Ok(Redirect::to(uri!(pages::history))), + None => Err(Status::NotFound.into()), + } + + // TODO: mark as deleted instead of removing + // Ok(past_sessions_tree.transaction(|tx_past_sessions| { + // match tx_past_sessions.get(&session_uuid_s)? { + // None => return Ok(Err(Status::NotFound)), + // Some(data) => { + // let mut past_session: past_sessions::V = deserialize(&data).unwrap(); + // } + // } + // Ok(Ok(Redirect::to(uri!(pages::history)))) + // })??) +} diff --git a/src/routes/pages.rs b/src/routes/pages.rs index 67a71c5..9d24b95 100644 --- a/src/routes/pages.rs +++ b/src/routes/pages.rs @@ -1,4 +1,4 @@ -use crate::database::v1::trees::{categories, past_sessions}; +use crate::database::latest::trees::{categories, past_sessions}; use crate::status_json::StatusJson; use bincode::deserialize; use rocket::{get, State}; @@ -35,6 +35,7 @@ pub fn history(db: State<'_, sled::Db>) -> Result { struct HistoryEntryContext { category: categories::V, session: past_sessions::V, + session_id: Uuid, duration: Duration, } @@ -60,19 +61,17 @@ pub fn history(db: State<'_, sled::Db>) -> Result { }) .collect::, _>>()??; - let mut context = dbg!(TemplateContext { + let mut context = TemplateContext { entries: past_sessions .into_iter() - .map(|(_, session)| { - let category = categories.get(&session.category).unwrap().clone(); - HistoryEntryContext { - duration: (session.ended - session.started).to_std().unwrap(), - category, - session, - } + .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); diff --git a/src/status_json.rs b/src/status_json.rs index c92d090..f07abb8 100644 --- a/src/status_json.rs +++ b/src/status_json.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use duplicate::duplicate; use log::{info, warn}; use rocket::http::Status; diff --git a/static/styles.css b/static/styles.css index 7ab328c..6fd26ec 100644 --- a/static/styles.css +++ b/static/styles.css @@ -100,3 +100,6 @@ ul.striped_list > li:nth-of-type(odd) { color: #9f2727; } +.history_entry_delete_button { + color: #aa0000; +} diff --git a/templates/history.hbs b/templates/history.hbs index 6d2acc9..4961921 100644 --- a/templates/history.hbs +++ b/templates/history.hbs @@ -17,13 +17,16 @@
    {{#each entries}}
  • - - for - {{pretty_seconds this.duration.secs}} - from - {{pretty_datetime this.session.started}} - to - {{pretty_datetime this.session.ended}} +
    + + under + {{pretty_seconds this.duration.secs}} + från + {{pretty_datetime this.session.started}} + tills + {{pretty_datetime this.session.ended}} + +
  • {{/each}}
diff --git a/templates/index.hbs b/templates/index.hbs index e8edd57..69d7d3c 100644 --- a/templates/index.hbs +++ b/templates/index.hbs @@ -20,10 +20,10 @@ // Get the corresponding route to activate/inactivate the category let url; if(active) { - url = "/set_category/" + id + "/inactive"; + url = "/category/" + id + "/end_session"; cl.remove(toggled_class); } else { - url = "/set_category/" + id + "/active"; + url = "/category/" + id + "/start_session"; cl.add(toggled_class); } @@ -42,10 +42,6 @@

stl

- {{#each categories}} -
- {{/each}} -
    {{#each categories}}