diff --git a/src/api/mod.rs b/src/api/mod.rs index 16beee1..7d6eb8c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,5 +1,5 @@ use axum::{routing::post, Json, Router}; -use jsonwebtoken::{encode, EncodingKey, Header}; +use jsonwebtoken::{encode, DecodingKey, EncodingKey, Header}; use rusqlite::Connection; use serde::Deserialize; use serde::Serialize; @@ -13,11 +13,12 @@ pub fn get_routes() -> Router { "/api", Router::new() .route("/register", post(register)) - .route("/login", post(login)), + .route("/login", post(login)) + .route("/change_username", post(change_username)), ) } -#[derive(Serialize)] +#[derive(Serialize, Deserialize)] struct Claims { account_id: usize, exp: usize, @@ -121,3 +122,41 @@ pub async fn login(Json(payload): Json) -> Json { } } } + +#[derive(Deserialize)] +pub struct ChangeUsernamePayload { + username: String, + token: String, +} + +fn get_account_id_from_jwt(token: &str) -> Result { + let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); + let token_data = jsonwebtoken::decode::( + token, + &DecodingKey::from_secret(jwt_secret.as_ref()), + &jsonwebtoken::Validation::default(), + )?; + Ok(token_data.claims.account_id) +} + +pub async fn change_username(Json(payload): Json) -> Json { + let account_id = match get_account_id_from_jwt(&payload.token) { + Ok(account_id) => account_id, + Err(_) => return Json(json!({ "error": "Invalid token" })), + }; + + let connection = Connection::open("database.db").expect("Failed to open database"); + match db::change_username(&connection, account_id, &payload.username) { + Ok(_) => {} + Err(rusqlite::Error::SqliteFailure(_, _)) => { + connection.close().expect("Failed to close"); + return Json(json!({ "error": "Username already taken" })); + } + Err(_) => { + connection.close().expect("Failed to close"); + return Json(json!({ "error": "Failed to change username" })); + } + } + connection.close().expect("Failed to close"); + Json(json!({ "success": "Username changed with success" })) +}