From 06815469b7ed1fa2aba5a50b2788e2c511aaebbe Mon Sep 17 00:00:00 2001
From: realaravinth <realaravinth@batsense.net>
Date: Wed, 14 Apr 2021 09:45:59 +0530
Subject: [PATCH] set email

---
 src/api/v1/auth.rs       | 41 +++++++++++++++++++++++++++++++++++
 src/api/v1/mod.rs        |  1 +
 src/api/v1/tests/auth.rs | 19 +++++++++++++++--
 src/errors.rs            |  6 ++++++
 src/main.rs              |  5 ++---
 src/settings.rs          | 46 ++++++++++++++++++++--------------------
 6 files changed, 90 insertions(+), 28 deletions(-)

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<Email>,
+
+    data: web::Data<Data>,
+) -> ServiceResult<impl Responder> {
+    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());
+//    }
+//}