diff --git a/Cargo.lock b/Cargo.lock index 0eced50..8450bc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "async-trait" version = "0.1.83" @@ -119,6 +134,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytes" version = "1.8.0" @@ -140,6 +161,27 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "darling" version = "0.20.10" @@ -230,6 +272,7 @@ version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e" dependencies = [ + "chrono", "diesel_derives", "libsqlite3-sys", "time", @@ -453,6 +496,29 @@ dependencies = [ "tower-service", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -475,6 +541,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -599,6 +674,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1128,6 +1212,61 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + [[package]] name = "winapi" version = "0.3.9" @@ -1150,6 +1289,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1237,6 +1385,7 @@ name = "work-timer" version = "0.1.0" dependencies = [ "axum", + "chrono", "deadpool-diesel", "diesel", "diesel_migrations", diff --git a/Cargo.toml b/Cargo.toml index 7cf9b07..c666fa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,14 +5,13 @@ edition = "2021" [dependencies] axum = "0.7.7" +chrono = { version = "0.4.38", features = ["serde"] } deadpool-diesel = {version = "0.6.1", features = ["sqlite"]} -diesel = { version = "2.2.4", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] } +diesel = { version = "2.2.4", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "chrono"] } dotenvy = "0.15.7" libsqlite3-sys = {version="0.30.1", features = ["bundled"]} serde = {version="1.0.214", features = ["derive"]} tokio = {version="1.41.0", features = ["full"]} tracing = "0.1.40" -tracing-subscriber = {version="0.3.18", features = ["env-filter"]} - -[dev-dependencies] diesel_migrations = "2.2.0" +tracing-subscriber = {version="0.3.18", features = ["env-filter"]} diff --git a/diesel.toml b/diesel.toml index 062027e..37d098f 100644 --- a/diesel.toml +++ b/diesel.toml @@ -4,7 +4,7 @@ [print_schema] file = "src/schema.rs" custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] -filter = { only_tables = ["users"] } +filter = { only_tables = ["work_periods"] } [migrations_directory] dir = "/home/server/Workspace/Projects/WorkTimer/Server/migrations" diff --git a/migrations/2024-11-02-143917_users/down.sql b/migrations/2024-11-02-143917_users/down.sql deleted file mode 100644 index 9951735..0000000 --- a/migrations/2024-11-02-143917_users/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE users diff --git a/migrations/2024-11-02-143917_users/up.sql b/migrations/2024-11-02-143917_users/up.sql deleted file mode 100644 index 6e9088c..0000000 --- a/migrations/2024-11-02-143917_users/up.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE users ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - username VARCHAR NOT NULL -) diff --git a/migrations/2024-11-02-143917_work_periods/down.sql b/migrations/2024-11-02-143917_work_periods/down.sql new file mode 100644 index 0000000..346b1bc --- /dev/null +++ b/migrations/2024-11-02-143917_work_periods/down.sql @@ -0,0 +1 @@ +DROP TABLE work_periods; diff --git a/migrations/2024-11-02-143917_work_periods/up.sql b/migrations/2024-11-02-143917_work_periods/up.sql new file mode 100644 index 0000000..7d18974 --- /dev/null +++ b/migrations/2024-11-02-143917_work_periods/up.sql @@ -0,0 +1,7 @@ +CREATE TABLE work_periods ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + project VARCHAR NOT NULL, + start_time TIMESTAMP NOT NULL, + end_time TIMESTAMP NOT NULL, + description VARCHAR +) diff --git a/src/main.rs b/src/main.rs index c459491..8171e8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,56 +1,51 @@ use diesel::prelude::*; use dotenvy::dotenv; use self::models::*; +use std::net::SocketAddr; use std::env; use axum::{ + extract::State, routing::{get, post}, http::StatusCode, Json, Router, }; -use serde::{Deserialize, Serialize}; +use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; +pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/"); pub mod models; pub mod schema; -pub fn establish_connection() -> SqliteConnection { - dotenv().ok(); - - let database_url = env::var("SQLITE_DATABASE_URL") - .or_else(|_| env::var("DATABASE_URL")) - .expect("DATABASE_URL must be set"); - - SqliteConnection::establish(&database_url) - .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) -} - #[tokio::main] async fn main() { - use self::schema::users::dsl::*; - // initialize tracing tracing_subscriber::fmt::init(); + dotenv().ok(); + let db_url = env::var("DATABASE_URL").unwrap(); + let manager = deadpool_diesel::sqlite::Manager::new(db_url, deadpool_diesel::Runtime::Tokio1); + let pool = deadpool_diesel::sqlite::Pool::builder(manager) + .build() + .unwrap(); - let connection = &mut establish_connection(); - let results = users - .limit(5) - .select(User::as_select()) - .load(connection) - .expect("Error loading users"); - - println!("Displaying {} users", results.len()); - for user in results { - println!("{:?}", user) + // Run migrations + { + let conn = pool.get().await.unwrap(); + conn.interact(|conn| conn.run_pending_migrations(MIGRATIONS).map(|_| ())) + .await + .unwrap() + .unwrap(); } // build our application with a route let app = Router::new() // `GET /` goes to `root` .route("/", get(root)) - // `POST /users` goes to `create_user` - .route("/users", post(create_user)); + .route("/history", post(add_period)) + .with_state(pool); // run our app with hyper, listening globally on port 3000 - let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + tracing::debug!("listening on {addr}"); + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); } @@ -59,21 +54,30 @@ async fn root() -> &'static str { "Hello, World!" } -async fn create_user( - // this argument tells axum to parse the request body - // as JSON into a `CreateUser` type - Json(payload): Json, -) -> (StatusCode, Json) { - let connection = &mut establish_connection(); - use crate::schema::users; +async fn add_period(State(pool): State, Json(payload): Json) -> Result<(StatusCode, Json), (StatusCode, String)> { + use crate::schema::work_periods; + + let conn = pool.get().await.map_err(internal_error)?; // insert your application logic here - let user = diesel::insert_into(users::table) - .values(&payload) - .returning(User::as_returning()) - .get_result(connection) - .expect("Error saving new user"); + let res = conn + .interact(move |conn| { + diesel::insert_into(work_periods::table) + .values(&payload) + .returning(WorkPeriod::as_returning()) + .get_result(conn) + }) + .await + .map_err(internal_error)? + .map_err(internal_error)?; // this will be converted into a JSON response // with a status code of `201 Created` - (StatusCode::CREATED, Json(user)) + Ok((StatusCode::CREATED, Json(res))) +} + +fn internal_error(err: E) -> (StatusCode, String) +where + E: std::error::Error, +{ + (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) } diff --git a/src/models.rs b/src/models.rs index 4697fc4..ca9237e 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,18 +1,25 @@ use diesel::prelude::*; use serde::{Deserialize, Serialize}; -use super::schema::users; +use super::schema::work_periods; +use chrono::NaiveDateTime; -#[derive(Queryable, Selectable, Serialize, Deserialize, Debug)] -#[diesel(table_name = crate::schema::users)] +#[derive(Queryable, Debug, Serialize, Deserialize, Selectable)] +#[diesel(table_name = crate::schema::work_periods)] #[diesel(check_for_backend(diesel::sqlite::Sqlite))] -pub struct User { +pub struct WorkPeriod { pub id: i32, - pub username: String, + pub project: String, + pub start_time: NaiveDateTime, + pub end_time: NaiveDateTime, + pub description: Option, } #[derive(Insertable, Serialize, Deserialize, Debug)] -#[diesel(table_name = users)] -pub struct NewUser { - pub username: String, +#[diesel(table_name = work_periods)] +pub struct NewPeriod { + pub project: String, + pub start_time: NaiveDateTime, + pub end_time: NaiveDateTime, + pub description: Option, } diff --git a/src/schema.rs b/src/schema.rs index 6d87667..73eabfd 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -1,8 +1,11 @@ // @generated automatically by Diesel CLI. diesel::table! { - users (id) { + work_periods (id) { id -> Integer, - username -> Text, + project -> Text, + start_time -> Timestamp, + end_time -> Timestamp, + description -> Nullable, } }