From a91266b70521f77f6a6ea6cc513a30df852677cb Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Sat, 7 Nov 2020 14:19:33 +0100 Subject: [PATCH] Add session edit page --- Cargo.lock | 176 ++++++++++++++++++++++++++++++++----- Cargo.toml | 8 +- src/main.rs | 2 + src/routes/api.rs | 77 +++++++++++----- src/routes/pages.rs | 32 ++++++- src/status_json.rs | 1 + templates/edit_session.hbs | 38 ++++++++ templates/history.hbs | 19 ++-- 8 files changed, 294 insertions(+), 59 deletions(-) create mode 100644 templates/edit_session.hbs diff --git a/Cargo.lock b/Cargo.lock index 57235f9..c1f5e4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,6 +90,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + [[package]] name = "autocfg" version = "1.0.1" @@ -210,6 +216,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "cloudabi" version = "0.1.0" @@ -236,7 +251,7 @@ dependencies = [ "hkdf", "hmac", "percent-encoding 2.1.0", - "rand", + "rand 0.7.3", "sha2", "time", ] @@ -256,7 +271,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg", + "autocfg 1.0.1", "cfg-if 0.1.10", "crossbeam-utils", "lazy_static", @@ -271,7 +286,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg", + "autocfg 1.0.1", "cfg-if 0.1.10", "lazy_static", ] @@ -417,6 +432,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -672,7 +693,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ - "autocfg", + "autocfg 1.0.1", "hashbrown", ] @@ -811,7 +832,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -830,7 +851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ "adler", - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -911,7 +932,7 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ - "autocfg", + "autocfg 1.0.1", "num-traits", ] @@ -921,7 +942,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -970,7 +991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" dependencies = [ "cfg-if 0.1.10", - "cloudabi", + "cloudabi 0.1.0", "instant", "libc", "redox_syscall", @@ -1175,6 +1196,25 @@ dependencies = [ "proc-macro2 1.0.24", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi 0.3.9", +] + [[package]] name = "rand" version = "0.7.3" @@ -1183,9 +1223,19 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", ] [[package]] @@ -1195,9 +1245,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.5.1" @@ -1207,13 +1272,84 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi 0.3.9", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi 0.0.3", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.9", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", ] [[package]] @@ -1289,6 +1425,7 @@ dependencies = [ "rocket", "serde", "serde_json", + "uuid", ] [[package]] @@ -1364,9 +1501,6 @@ name = "serde" version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" -dependencies = [ - "serde_derive", -] [[package]] name = "serde_derive" @@ -1450,7 +1584,7 @@ checksum = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028" [[package]] name = "stl" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bincode", "chrono", @@ -1636,11 +1770,11 @@ dependencies = [ [[package]] name = "uuid" -version = "0.8.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" dependencies = [ - "rand", + "rand 0.6.5", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 80b4ed4..cf29d36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "stl" -description = "studielogg, pronounced 'stell', aka scuffed toggl" -version = "0.1.1" +description = "studielogg aka scuffed toggl" +version = "0.2.0" authors = ["Joakim Hulthe "] license = "MPL-2.0" edition = "2018" @@ -16,7 +16,7 @@ futures = "0.3" chrono = { version = "0.4", features = ["serde"] } sled = "0.34" semver = "0.11" -uuid = { version = "0.8", features = ["serde", "v4"] } +uuid = { version = "0.7", features = ["serde", "v4"] } duplicate = "0.2" bincode = "1" handlebars = "1" @@ -30,4 +30,4 @@ version = "0.4" version = "0.4" #git = "https://github.com/SergioBenitez/Rocket" #branch = "master" -features = ["handlebars_templates"] +features = ["handlebars_templates", "uuid"] diff --git a/src/main.rs b/src/main.rs index 5df66dd..6e52c97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,8 @@ fn main() -> io::Result<()> { rocket::routes![ routes::pages::index, routes::pages::history, + routes::pages::session_edit, + routes::api::edit_session, routes::api::create_category, routes::api::start_session, routes::api::end_session, diff --git a/src/routes/api.rs b/src/routes/api.rs index 73800ce..8e1d519 100644 --- a/src/routes/api.rs +++ b/src/routes/api.rs @@ -2,13 +2,14 @@ use crate::database::latest::trees::{categories, past_sessions}; use crate::routes::pages; use crate::status_json::StatusJson; use bincode::{deserialize, serialize}; +use chrono::NaiveDateTime; use chrono::{Duration, Utc}; use rocket::http::Status; use rocket::request::{Form, FromForm}; use rocket::response::Redirect; use rocket::{post, uri, State}; +use rocket_contrib::uuid::Uuid; use sled::Transactional; -use uuid::Uuid; #[derive(FromForm)] pub struct NewCategory { @@ -25,7 +26,7 @@ pub fn create_category( let categories_tree = db.open_tree(categories::NAME)?; categories_tree.insert( - serialize(&Uuid::new_v4())?, + serialize(&uuid::Uuid::new_v4())?, serialize(&categories::V { name: category.name, color: category.color, @@ -38,29 +39,25 @@ pub fn create_category( #[post("/category//start_session")] pub fn start_session( - category_uuid: String, + category_uuid: Uuid, db: State<'_, sled::Db>, ) -> Result { toggle_category_session(category_uuid, true, db) } #[post("/category//end_session")] -pub fn end_session( - category_uuid: String, - db: State<'_, sled::Db>, -) -> Result { +pub fn end_session(category_uuid: Uuid, db: State<'_, sled::Db>) -> Result { toggle_category_session(category_uuid, false, db) } #[post("/category//bump_session/minutes/")] pub fn bump_session( - category_uuid: String, + category_uuid: Uuid, minutes: i64, db: State<'_, sled::Db>, ) -> Result { let duration = Duration::minutes(minutes); - let category_uuid = Uuid::parse_str(&category_uuid)?; - let category_uuid_s = sled::IVec::from(serialize(&category_uuid)?); + let category_uuid_s = sled::IVec::from(serialize(&category_uuid.into_inner())?); let categories_tree = db.open_tree(categories::NAME)?; @@ -75,7 +72,12 @@ pub fn bump_session( tx_categories.insert(&category_uuid_s, serialize(&category).unwrap())?; Ok(Ok(Redirect::to(uri!(pages::index)))) } - None => return Ok(Err(StatusJson::new(Status::BadRequest, "No active session"))), + None => { + return Ok(Err(StatusJson::new( + Status::BadRequest, + "No active session", + ))) + } } } } @@ -83,12 +85,11 @@ pub fn bump_session( } pub fn toggle_category_session( - category_uuid: String, + category_uuid: Uuid, set_active: bool, db: State<'_, sled::Db>, ) -> Result { - let category_uuid = Uuid::parse_str(&category_uuid)?; - let category_uuid_s = sled::IVec::from(serialize(&category_uuid)?); + let category_uuid_s = sled::IVec::from(serialize(&category_uuid.into_inner())?); let categories_tree = db.open_tree(categories::NAME)?; let past_sessions_tree = db.open_tree(past_sessions::NAME)?; @@ -106,9 +107,9 @@ pub fn toggle_category_session( // only save sessions longer than 5 minutes let duration = now - started; if duration > Duration::minutes(5) { - let session_uuid = serialize(&Uuid::new_v4()).unwrap(); + let session_uuid = serialize(&uuid::Uuid::new_v4()).unwrap(); let past_session = past_sessions::V { - category: category_uuid, + category: category_uuid.into_inner(), started, ended: now, }; @@ -134,13 +135,47 @@ pub fn toggle_category_session( )??) } -#[post("/session//delete")] -pub fn delete_session( - session_uuid: String, +#[derive(Debug, FromForm)] +pub struct EditSession { + category: Uuid, + started: String, + ended: String, +} + +#[post("/session//edit", data = "")] +pub fn edit_session( + session_uuid: Uuid, + session: Form, db: State<'_, sled::Db>, ) -> Result { - let session_uuid = Uuid::parse_str(&session_uuid)?; - let session_uuid_s = sled::IVec::from(serialize(&session_uuid)?); + let session_uuid_s = sled::IVec::from(serialize(&session_uuid.into_inner())?); + + dbg!(&session); + + let session = past_sessions::V { + category: session.category.into_inner(), + started: NaiveDateTime::parse_from_str(&session.started, "%Y-%m-%d %H:%M")?, + ended: NaiveDateTime::parse_from_str(&session.ended, "%Y-%m-%d %H:%M")?, + }; + + if session.started >= session.ended { + return Err(StatusJson::new( + Status::BadRequest, + "started must be earlier than ended", + )); + } + + db.open_tree(past_sessions::NAME)? + .insert(session_uuid_s, serialize(&session)?)?; + + // FIXME: Uuid does not implement FromUriParam for some reason... File an issue? + //Ok(Redirect::to(uri!(pages::session_edit: session_uuid))) + Ok(Redirect::to(format!("/session/{}/edit", session_uuid))) +} + +#[post("/session//delete")] +pub fn delete_session(session_uuid: Uuid, db: State<'_, sled::Db>) -> Result { + let session_uuid_s = sled::IVec::from(serialize(&session_uuid.into_inner())?); let past_sessions_tree = db.open_tree(past_sessions::NAME)?; diff --git a/src/routes/pages.rs b/src/routes/pages.rs index 9d24b95..560b3d8 100644 --- a/src/routes/pages.rs +++ b/src/routes/pages.rs @@ -1,18 +1,20 @@ use crate::database::latest::trees::{categories, past_sessions}; use crate::status_json::StatusJson; use bincode::deserialize; +use bincode::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::HashMap; use std::time::Duration; -use uuid::Uuid; #[get("/")] pub fn index(db: State<'_, sled::Db>) -> Result { #[derive(Debug, Serialize, Deserialize)] struct TemplateContext { - categories: Vec<(Uuid, categories::V)>, + categories: Vec<(uuid::Uuid, categories::V)>, } let categories_tree = db.open_tree(categories::NAME)?; @@ -29,13 +31,37 @@ pub fn index(db: State<'_, sled::Db>) -> Result { Ok(Template::render("index", &context)) } +#[get("/session//edit")] +pub fn session_edit(session_uuid: Uuid, db: State<'_, sled::Db>) -> Result { + #[derive(Debug, Serialize, Deserialize)] + struct SessionPageContext { + session: past_sessions::V, + session_id: uuid::Uuid, + } + + let session_uuid_s = sled::IVec::from(serialize(&session_uuid.into_inner())?); + + let past_sessions_tree = db.open_tree(past_sessions::NAME)?; + match past_sessions_tree.get(session_uuid_s)? { + None => Err(Status::NotFound)?, + 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(db: State<'_, sled::Db>) -> Result { #[derive(Debug, Serialize, Deserialize)] struct HistoryEntryContext { category: categories::V, session: past_sessions::V, - session_id: Uuid, + session_id: uuid::Uuid, duration: Duration, } diff --git a/src/status_json.rs b/src/status_json.rs index f07abb8..93e09fc 100644 --- a/src/status_json.rs +++ b/src/status_json.rs @@ -67,6 +67,7 @@ impl<'r> Responder<'r> for StatusJson { [ Status::InternalServerError ] [ sled::transaction::TransactionError ]; [ Status::InternalServerError ] [ bincode::Error ]; [ Status::BadRequest ] [ uuid::Error ]; + [ Status::BadRequest ] [ chrono::ParseError ]; )] impl From for StatusJson { fn from(e: T) -> StatusJson { diff --git a/templates/edit_session.hbs b/templates/edit_session.hbs new file mode 100644 index 0000000..a7d63d6 --- /dev/null +++ b/templates/edit_session.hbs @@ -0,0 +1,38 @@ + + + + + + + + + + + + stl + + + +

stl

+ +
+ tillbaka +
+
+
+ + Started: + +
+ Ended: + +
+ +
+
+
+ +
+
+ + diff --git a/templates/history.hbs b/templates/history.hbs index 4961921..e938cf4 100644 --- a/templates/history.hbs +++ b/templates/history.hbs @@ -17,16 +17,15 @@
    {{#each entries}}
  • -
    - - under - {{pretty_seconds this.duration.secs}} - från - {{pretty_datetime this.session.started}} - tills - {{pretty_datetime this.session.ended}} - -
    + + under + {{pretty_seconds this.duration.secs}} + från + {{pretty_datetime this.session.started}} + tills + {{pretty_datetime this.session.ended}} + --- + ändra
  • {{/each}}