diff --git a/trifid-api/src/email.rs b/trifid-api/src/email.rs index ee9dd80..47200d8 100644 --- a/trifid-api/src/email.rs +++ b/trifid-api/src/email.rs @@ -3,11 +3,14 @@ use log::info; use sqlx::PgPool; use uuid::Uuid; use crate::config::TFConfig; +use std::time::SystemTime; +use std::time::UNIX_EPOCH; + // https://admin.defined.net/auth/magic-link?email=coredoescode%40gmail.com&token=ml-ckBsgw_5IdK5VYgseBYcoV_v_cQjtdq1re_RhDu_MKg pub async fn send_magic_link(id: i64, email: String, db: &PgPool, config: &TFConfig) -> Result<(), Box> { let otp = Uuid::new_v4().to_string(); - let otp_url = format!("{}/{}", config.base, urlencoding::encode(&format!("/auth/magic-link?email={}&token={}", email.clone(), otp.clone()))); - sqlx::query!("INSERT INTO magic_links (id, user_id, expires_on) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;", otp, id, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64 + config.config.magic_links_valid_for).await?; + let otp_url = config.base.join(&format!("/auth/magic-link?email={}&token={}", urlencoding::encode(&email.clone()), otp.clone())).unwrap(); + sqlx::query!("INSERT INTO magic_links (id, user_id, expires_on) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING;", otp, id as i32, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i32 + config.magic_links_valid_for as i32).execute(db).await?; // TODO: send email info!("sent magic link {} to {}, valid for {} seconds", otp_url, email.clone(), config.magic_links_valid_for); Ok(()) diff --git a/trifid-api/src/routes/v1/signup.rs b/trifid-api/src/routes/v1/signup.rs index b2c6574..5e46817 100644 --- a/trifid-api/src/routes/v1/signup.rs +++ b/trifid-api/src/routes/v1/signup.rs @@ -31,15 +31,27 @@ created_on TIMESTAMP NOT NULL, */ #[post("/v1/signup", data = "")] pub async fn signup_request(req: Json, pool: &State, config: &State) -> Result<(ContentType, Json), (Status, String)> { - match sqlx::query!("INSERT INTO users (email, created_on, banned, ban_reason, totp_secret, totp_otpurl, totp_verified) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id ON CONFLICT DO NOTHING;", req.email, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64, 0, "", "", "", 0).execute(pool.inner()).await { - Ok(_) => (), + // figure out if the user already exists + let mut id = -1; + match sqlx::query!("SELECT id FROM users WHERE email = $1", req.email.clone()).fetch_optional(pool.inner()).await { + Ok(res) => if let Some(r) = res { id = r.id as i64 }, Err(e) => { return Err((Status::InternalServerError, format!("{{\"errors\":[{{\"code\":\"{}\",\"message\":\"{} - {}\"}}]}}", "ERR_QL_QUERY_FAILED", "an error occurred while running the graphql query", e))) } - }; + } + + if id == -1 { + let id_res = match sqlx::query!("INSERT INTO users (email, created_on, banned, ban_reason, totp_secret, totp_otpurl, totp_verified) VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT DO NOTHING RETURNING id;", req.email, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64, 0, "", "", "", 0).fetch_one(pool.inner()).await { + Ok(row) => row.id, + Err(e) => { + return Err((Status::InternalServerError, format!("{{\"errors\":[{{\"code\":\"{}\",\"message\":\"{} - {}\"}}]}}", "ERR_QL_QUERY_FAILED", "an error occurred while running the graphql query", e))) + } + }; + id = id_res as i64; + } // send magic link to email - match send_magic_link(req.email.clone(), pool.inner(), config.inner()).await { + match send_magic_link(id, req.email.clone(), pool.inner(), config.inner()).await { Ok(_) => (), Err(e) => { return Err((Status::InternalServerError, format!("{{\"errors\":[{{\"code\":\"{}\",\"message\":\"{} - {}\"}}]}}", "ERR_QL_QUERY_FAILED", "an error occurred while running the graphql query", e)))