From 3cb122306a63f6a60458af7e53aef150332c443e Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 5 Feb 2025 02:40:23 -0800 Subject: [PATCH] use sqlx::query! macro --- ...634a6970eeb4e1d3395f045ded747f0ce9d2a.json | 12 ++ ...e55788deb3a996b8e51d651a9e4a07b1483b4.json | 20 +++ ...843384da66c0cac7d6f8f929470c72284d8c8.json | 12 ++ src/user.rs | 124 +++++++++--------- 4 files changed, 106 insertions(+), 62 deletions(-) create mode 100644 .sqlx/query-73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a.json create mode 100644 .sqlx/query-b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4.json create mode 100644 .sqlx/query-bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8.json diff --git a/.sqlx/query-73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a.json b/.sqlx/query-73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a.json new file mode 100644 index 0000000..3427c65 --- /dev/null +++ b/.sqlx/query-73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM users WHERE id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a" +} diff --git a/.sqlx/query-b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4.json b/.sqlx/query-b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4.json new file mode 100644 index 0000000..ae4e442 --- /dev/null +++ b/.sqlx/query-b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT COUNT(*) as \"count!: i32\"\n FROM users\n ", + "describe": { + "columns": [ + { + "name": "count!: i32", + "ordinal": 0, + "type_info": "Int" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4" +} diff --git a/.sqlx/query-bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8.json b/.sqlx/query-bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8.json new file mode 100644 index 0000000..803acf6 --- /dev/null +++ b/.sqlx/query-bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin) \n VALUES (?, ?, ?, ?, ?, ?, ?)\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 7 + }, + "nullable": [] + }, + "hash": "bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8" +} diff --git a/src/user.rs b/src/user.rs index bb213dc..3196a06 100644 --- a/src/user.rs +++ b/src/user.rs @@ -45,19 +45,22 @@ impl User { where E: sqlx::Executor<'a, Database = sqlx::Sqlite>, { - sqlx::query( + let id_str = self.id.to_string(); + let created_at_str = self.created_at.to_rfc3339(); + + sqlx::query!( r#" INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) + VALUES (?, ?, ?, ?, ?, ?, ?) "#, + id_str, + self.username, + self.password_hash, + self.email, + self.display_name, + created_at_str, + self.admin ) - .bind(self.id.to_string()) - .bind(self.username.clone()) - .bind(self.password_hash.clone()) - .bind(self.email.clone()) - .bind(self.display_name.clone()) - .bind(self.created_at.to_rfc3339()) - .bind(self.admin) .execute(executor) .await?; @@ -173,12 +176,15 @@ pub async fn delete_user(mut db: Connection, user_id: &str) -> Status { Err(_) => return Status::BadRequest, }; - let query = sqlx::query("DELETE FROM users WHERE id = ?") - .bind(uuid.to_string()) - .execute(&mut **db) - .await; + let id_str = uuid.to_string(); + let result = sqlx::query!( + "DELETE FROM users WHERE id = ?", + id_str + ) + .execute(&mut **db) + .await; - match query { + match result { Ok(result) => { if result.rows_affected() > 0 { Status::NoContent @@ -201,6 +207,7 @@ pub async fn login( sessions: &State, ) -> Result, Status> { let creds = credentials.into_inner(); + let username = creds.username.clone(); // Find user by username let user = sqlx::query!( @@ -212,7 +219,7 @@ pub async fn login( FROM users WHERE username = ? "#, - creds.username + username ) .fetch_optional(&mut **db) .await @@ -300,19 +307,21 @@ impl<'r> rocket::request::FromRequest<'r> for AuthenticatedUser { #[get("/setup")] pub async fn setup_page(mut db: Connection) -> Result { // Check if any users exist - let count = sqlx::query!("SELECT COUNT(*) as count FROM users") - .fetch_one(&mut **db) - .await - .map_err(|_| Status::InternalServerError)? - .count; + let count = sqlx::query!( + r#" + SELECT COUNT(*) as "count!: i32" + FROM users + "# + ) + .fetch_one(&mut **db) + .await + .map_err(|_| Status::InternalServerError)?; - if count > 0 { - // If users exist, redirect to login - Err(Status::SeeOther) - } else { - // Show setup page - Ok(Template::render("setup", context! {})) + if count.count > 0 { + return Err(Status::Forbidden); } + + Ok(Template::render("setup", context! {})) } #[post("/setup", data = "")] @@ -320,33 +329,33 @@ pub async fn setup( mut db: Connection, new_user: Json, ) -> Result> { - let new_user = new_user.into_inner(); - // Check if any users exist - let count = sqlx::query!("SELECT COUNT(*) as count FROM users") - .fetch_one(&mut **db) - .await - .map_err(|e| { - eprintln!("Database error: {}", e); - Json(SetupError { - error: "Internal server error".to_string(), - }) - })? - .count; + let count = sqlx::query!( + r#" + SELECT COUNT(*) as "count!: i32" + FROM users + "# + ) + .fetch_one(&mut **db) + .await + .map_err(|_| { + Json(SetupError { + error: "Database error".to_string(), + }) + })?; - if count > 0 { + if count.count > 0 { return Err(Json(SetupError { - error: "Setup has already been completed".to_string(), + error: "Setup already completed".to_string(), })); } - let password = new_user.password.as_bytes(); + let new_user = new_user.into_inner(); - // Hash the password - let password_hash = bcrypt::hash(password, bcrypt::DEFAULT_COST).map_err(|e| { - eprintln!("Password hashing error: {}", e); + // Hash the password - we'll use bcrypt + let password_hash = bcrypt::hash(new_user.password.as_bytes(), bcrypt::DEFAULT_COST).map_err(|_| { Json(SetupError { - error: "Failed to process password".to_string(), + error: "Failed to hash password".to_string(), }) })?; @@ -356,22 +365,13 @@ pub async fn setup( new_user.email, new_user.display_name, ); - user.admin = true; // This is an admin user + user.admin = true; - match user.write_to_database(&mut **db).await { - Ok(_) => Ok(Status::Created), - Err(e) => { - error!("Database error: {}", e); - match e { - sqlx::Error::Database(db_err) if db_err.is_unique_violation() => { - Err(Json(SetupError { - error: "Username already exists".to_string(), - })) - } - _ => Err(Json(SetupError { - error: "Failed to create user".to_string(), - })), - } - } - } + user.write_to_database(&mut **db) + .await + .map_err(|_| Json(SetupError { + error: "Failed to create user".to_string(), + }))?; + + Ok(Status::Created) }