diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 83 |
1 files changed, 76 insertions, 7 deletions
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<SignupForm>, ) -> Result<HttpResponse> { 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<String>, } #[post("/login")] async fn post_login(form: web::Form<LoginForm>) -> Result<HttpResponse> { - 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<Pinussy>) -> Result<HttpResponse> { let users: Vec<User> = sqlx::query_as("select * from users") |