diff --git a/src/api/v1/auth.rs b/src/api/v1/auth.rs index 955e108d..6e454946 100644 --- a/src/api/v1/auth.rs +++ b/src/api/v1/auth.rs @@ -205,6 +205,47 @@ pub async fn update_user_secret( Ok(HttpResponse::Ok()) } +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Email { + pub email: String, +} + +#[post("/api/v1/account/email/")] +pub async fn set_email( + id: Identity, + + payload: web::Json, + + data: web::Data, +) -> ServiceResult { + is_authenticated(&id)?; + + let username = id.identity().unwrap(); + + data.creds.email(Some(&payload.email))?; + + let res = sqlx::query!( + "UPDATE mcaptcha_users set email = $1 + WHERE name = $2", + &payload.email, + &username, + ) + .execute(&data.db) + .await; + if !res.is_ok() { + if let Err(sqlx::Error::Database(err)) = res { + if err.code() == Some(Cow::from("23505")) + && err.message().contains("mcaptcha_users_email_key") + { + Err(ServiceError::EmailTaken)? + } else { + Err(sqlx::Error::Database(err))? + } + }; + } + Ok(HttpResponse::Ok()) +} + #[post("/api/v1/signout")] pub async fn signout(id: Identity) -> impl Responder { if let Some(_) = id.identity() { diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs index e20a7759..658ba635 100644 --- a/src/api/v1/mod.rs +++ b/src/api/v1/mod.rs @@ -36,6 +36,7 @@ pub fn services(cfg: &mut ServiceConfig) { cfg.service(auth::email_exists); cfg.service(auth::get_secret); cfg.service(auth::update_user_secret); + cfg.service(auth::set_email); // mcaptcha cfg.service(mcaptcha::mcaptcha::add_mcaptcha); diff --git a/src/api/v1/tests/auth.rs b/src/api/v1/tests/auth.rs index 9372cc87..421d2f5a 100644 --- a/src/api/v1/tests/auth.rs +++ b/src/api/v1/tests/auth.rs @@ -134,10 +134,12 @@ async fn auth_works() { } #[actix_rt::test] -async fn del_userworks() { +async fn email_udpate_and_del_userworks() { const NAME: &str = "testuser2"; const PASSWORD: &str = "longpassword2"; const EMAIL: &str = "testuser1@a.com2"; + const DEL_URL: &str = "/api/v1/account/delete"; + const EMAIL_UPDATE: &str = "/api/v1/account/email/"; { let data = Data::new().await; @@ -148,13 +150,26 @@ async fn del_userworks() { let cookies = get_cookie!(signin_resp); let mut app = get_app!(data).await; + let email_payload = Email { + email: EMAIL.into(), + }; + let email_update_resp = test::call_service( + &mut app, + post_request!(&email_payload, EMAIL_UPDATE) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + + assert_eq!(email_update_resp.status(), StatusCode::OK); + let payload = Password { password: creds.password, }; let delete_user_resp = test::call_service( &mut app, - post_request!(&payload, "/api/v1/account/delete") + post_request!(&payload, DEL_URL) .cookie(cookies) .to_request(), ) diff --git a/src/errors.rs b/src/errors.rs index 2a0cf4a5..80cb548a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -77,6 +77,11 @@ pub enum ServiceError { /// when the a username is already taken #[display(fmt = "Username not available")] UsernameTaken, + + /// email is already taken + #[display(fmt = "Email not available")] + EmailTaken, + /// when the a token name is already taken /// token not found #[display(fmt = "Token not found. Is token registered?")] @@ -122,6 +127,7 @@ impl ResponseError for ServiceError { ServiceError::PasswordTooLong => StatusCode::BAD_REQUEST, ServiceError::UsernameTaken => StatusCode::BAD_REQUEST, + ServiceError::EmailTaken => StatusCode::BAD_REQUEST, ServiceError::TokenNotFound => StatusCode::NOT_FOUND, ServiceError::CaptchaError(e) => match e { diff --git a/src/main.rs b/src/main.rs index 5f107a81..e655a75f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,11 +16,10 @@ */ use std::env; -use actix_cors::Cors; use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::{ - client::Client, error::InternalError, http::StatusCode, middleware, web::scope, - web::JsonConfig, App, HttpServer, + client::Client, error::InternalError, http::StatusCode, middleware, web::JsonConfig, App, + HttpServer, }; //use awc::Client; use cache_buster::Files as FileMap; diff --git a/src/settings.rs b/src/settings.rs index 35853ab8..935fb744 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -44,14 +44,14 @@ impl Server { format!("{}:{}", self.ip, self.port) } - fn check_url_prefix(&mut self) { - if let Some(prefix) = self.url_prefix.clone() { - self.url_prefix = Some(prefix.trim().into()); - if prefix.trim().is_empty() { - self.url_prefix = None; - } - } - } + //fn check_url_prefix(&mut self) { + // if let Some(prefix) = self.url_prefix.clone() { + // self.url_prefix = Some(prefix.trim().into()); + // if prefix.trim().is_empty() { + // self.url_prefix = None; + // } + // } + //} } #[derive(Debug, Clone, Deserialize)] @@ -173,18 +173,18 @@ fn set_database_url(s: &mut Config) { .expect("Couldn't set databse url"); } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn url_prefix_test() { - let mut settings = Settings::new().unwrap(); - assert!(settings.server.url_prefix.is_none()); - settings.server.url_prefix = Some("test".into()); - settings.server.check_url_prefix(); - settings.server.url_prefix = Some(" ".into()); - settings.server.check_url_prefix(); - assert!(settings.server.url_prefix.is_none()); - } -} +//#[cfg(test)] +//mod tests { +// use super::*; +// +// #[test] +// fn url_prefix_test() { +// let mut settings = Settings::new().unwrap(); +// assert!(settings.server.url_prefix.is_none()); +// settings.server.url_prefix = Some("test".into()); +// settings.server.check_url_prefix(); +// settings.server.url_prefix = Some(" ".into()); +// settings.server.check_url_prefix(); +// assert!(settings.server.url_prefix.is_none()); +// } +//}