diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/users.rs | 54 | ||||
| -rw-r--r-- | src/services/db.rs | 43 |
2 files changed, 88 insertions, 9 deletions
diff --git a/src/api/users.rs b/src/api/users.rs index edade22..d9859e7 100644 --- a/src/api/users.rs +++ b/src/api/users.rs @@ -1,5 +1,6 @@ use actix_web::http::{header, StatusCode}; use actix_web::{post, put, web, HttpResponse, ResponseError, Scope}; +use exun::RawUnexpected; use raise::yeet; use serde::Deserialize; use sqlx::MySqlPool; @@ -69,11 +70,7 @@ async fn update_user( let username = body.username.clone(); let password = PasswordHash::new(&body.password).unwrap(); - let old_username = db::get_username(conn, user_id) - .await - .unwrap() - .unwrap() - .into_boxed_str(); + let old_username = db::get_username(conn, user_id).await.unwrap().unwrap(); if username != old_username && db::username_is_used(conn, &body.username).await.unwrap() { yeet!(UsernameTakenError { username }) } @@ -84,7 +81,7 @@ async fn update_user( password, }; - db::update_username(conn, &user).await.unwrap(); + db::update_user(conn, &user).await.unwrap(); let response = HttpResponse::NoContent() .insert_header((header::LOCATION, format!("users/{user_id}"))) @@ -93,6 +90,51 @@ async fn update_user( Ok(response) } +#[put("/{user_id}/username")] +async fn update_username( + user_id: web::Path<Uuid>, + body: web::Json<Box<str>>, + conn: web::Data<MySqlPool>, +) -> Result<HttpResponse, UsernameTakenError> { + let conn = conn.get_ref(); + + let user_id = user_id.to_owned(); + let username = body.clone(); + + let old_username = db::get_username(conn, user_id).await.unwrap().unwrap(); + if username != old_username && db::username_is_used(conn, &body).await.unwrap() { + yeet!(UsernameTakenError { username }) + } + + db::update_username(conn, user_id, &body).await.unwrap(); + + let response = HttpResponse::NoContent() + .insert_header((header::LOCATION, format!("users/{user_id}/username"))) + .finish(); + + Ok(response) +} + +#[put("/{user_id}/password")] +async fn update_password( + user_id: web::Path<Uuid>, + body: web::Json<Box<str>>, + conn: web::Data<MySqlPool>, +) -> HttpResponse { + let conn = conn.get_ref(); + + let user_id = user_id.to_owned(); + let password = PasswordHash::new(&body).unwrap(); + + db::update_password(conn, user_id, &password).await.unwrap(); + + let response = HttpResponse::NoContent() + .insert_header((header::LOCATION, format!("users/{user_id}/password"))) + .finish(); + + response +} + pub fn service() -> Scope { web::scope("/users") .service(create_user) diff --git a/src/services/db.rs b/src/services/db.rs index b508e1b..a6571b5 100644 --- a/src/services/db.rs +++ b/src/services/db.rs @@ -4,6 +4,8 @@ use uuid::Uuid; use crate::models::User; +use super::crypto::PasswordHash; + /// Intialize the connection pool pub async fn initialize(db: &str, user: &str, password: &str) -> Result<MySqlPool, RawUnexpected> { let url = format!("mysql://{user}:{password}@localhost/{db}"); @@ -41,10 +43,11 @@ pub async fn username_is_used<'c>( pub async fn get_username<'c>( conn: impl Executor<'c, Database = MySql>, user_id: Uuid, -) -> Result<Option<String>, RawUnexpected> { +) -> Result<Option<Box<str>>, RawUnexpected> { let username = query_scalar!(r"SELECT username FROM users where user_id = ?", user_id) .fetch_optional(conn) - .await?; + .await? + .map(String::into_boxed_str); Ok(username) } @@ -66,7 +69,7 @@ pub async fn new_user<'c>( .await } -pub async fn update_username<'c>( +pub async fn update_user<'c>( conn: impl Executor<'c, Database = MySql>, user: &User, ) -> Result<MySqlQueryResult, sqlx::Error> { @@ -86,3 +89,37 @@ pub async fn update_username<'c>( .execute(conn) .await } + +pub async fn update_username<'c>( + conn: impl Executor<'c, Database = MySql>, + user_id: Uuid, + username: &str, +) -> Result<MySqlQueryResult, sqlx::Error> { + query!( + r"UPDATE users SET username = ? WHERE user_id = ?", + username, + user_id + ) + .execute(conn) + .await +} + +pub async fn update_password<'c>( + conn: impl Executor<'c, Database = MySql>, + user_id: Uuid, + password: &PasswordHash, +) -> Result<MySqlQueryResult, sqlx::Error> { + query!( + r"UPDATE users SET + password_hash = ?, + password_salt = ?, + password_version = ? + WHERE user_id = ?", + password.hash(), + password.salt(), + password.version(), + user_id + ) + .execute(conn) + .await +} |
