From 2407c1a4a55d17817b31f7ca5cac9d68b27f536c Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Mon, 11 Dec 2023 06:02:00 +0000 Subject: implement signup --- src/main.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index eb7f0e8..c1520ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers}; use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, ResponseError}; use bcrypt::{hash, verify, DEFAULT_COST}; use serde::Deserialize; +use sqlx::postgres::PgDatabaseError; use sqlx::{postgres::PgPoolOptions, Pool, Postgres}; use templates::statics::StaticFile; @@ -67,7 +68,7 @@ async fn home() -> HttpResponse { #[get("/signup")] async fn get_signup() -> HttpResponse { - HttpResponse::Ok().body(render!(templates::signup_html).unwrap()) + HttpResponse::Ok().body(render!(templates::signup_html, None).unwrap()) } #[derive(Deserialize)] @@ -82,31 +83,78 @@ async fn post_signup( form: web::Form, ) -> Result { let password_hash = hash(&form.password, DEFAULT_COST)?; - sqlx::query!( + match sqlx::query!( "insert into users(username, password) values ($1, $2)", &form.username, password_hash ) .execute(&state.db) - .await?; - Ok(HttpResponse::Ok().body(render!(templates::signup_html).unwrap())) + .await + { + Ok(_) => { + return Ok(HttpResponse::Ok().body( + render!( + templates::signup_html, + Some(Notification { + kind: NotificationKind::Info, + message: format!("you have successfully registered as {}", &form.username) + }) + ) + .unwrap(), + )) + } + Err(e) => { + match e { + sqlx::Error::Database(e) => { + if e.is_unique_violation() { + return Ok(HttpResponse::Conflict().body( + render!( + templates::signup_html, + Some(Notification { + kind: NotificationKind::Error, + message: format!( + "error: the username \"{}\" already exists", + &form.username + ) + }) + ) + .unwrap(), + )); + } + } + // TODO: log error + _ => {} + } + return Ok(HttpResponse::InternalServerError().body( + render!( + templates::signup_html, + Some(Notification { + kind: NotificationKind::Error, + message: "there was an internal server error. please try again later." + .to_owned() + }) + ) + .unwrap(), + )); + } + }; } #[get("/login")] async fn get_login() -> HttpResponse { - HttpResponse::Ok().body(render!(templates::login_html).unwrap()) + HttpResponse::Ok().body(render!(templates::login_html, None).unwrap()) } #[derive(Deserialize)] struct LoginForm { username: String, password: String, - rememberme: bool, + rememberme: Option, } #[post("/login")] async fn post_login(form: web::Form) -> Result { - Ok(HttpResponse::Ok().body(render!(templates::login_html).unwrap())) + Ok(HttpResponse::Ok().body(render!(templates::login_html, None).unwrap())) } #[derive(sqlx::Type)] @@ -129,6 +177,27 @@ pub struct User { admin: bool, } +pub enum NotificationKind { + Info, + Warning, + Error, +} + +impl std::fmt::Display for NotificationKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + NotificationKind::Info => f.write_str("info"), + NotificationKind::Warning => f.write_str("warning"), + NotificationKind::Error => f.write_str("error"), + } + } +} + +pub struct Notification { + kind: NotificationKind, + message: String, +} + #[get("/users")] async fn get_users(state: web::Data) -> Result { let users: Vec = sqlx::query_as("select * from users") -- cgit