summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/users.rs54
-rw-r--r--src/services/db.rs43
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
+}