use actix_session::Session; use actix_web::http::header::LOCATION; use actix_web::{get, post, web, HttpResponse}; use bcrypt::verify; use serde::Deserialize; use crate::notification::{Kind, Notification}; use crate::templates; use crate::Pinussy; use crate::Result; #[get("/login")] async fn get() -> HttpResponse { HttpResponse::Ok().body(render!(templates::login_html, None).unwrap()) } #[derive(Deserialize)] struct LoginForm { username: String, password: String, rememberme: Option, } #[post("/login")] async fn post( state: web::Data, session: Session, form: web::Form, ) -> Result { match sqlx::query!( "select id, password from users where username = $1", &form.username ) .fetch_one(&state.db) .await { Ok(user) => { let password_hash: String = user.password; if verify(&form.password, &password_hash)? { session.insert("user_id", user.id)?; return Ok(HttpResponse::SeeOther() .insert_header((LOCATION, "/")) .finish()); } else { return Ok(HttpResponse::Unauthorized().body( render!( templates::login_html, Some(Notification { kind: Kind::Error, message: "that password is incorrect".to_owned() }) ) .unwrap(), )); } } Err(sqlx::Error::RowNotFound) => { return Ok(HttpResponse::NotFound().body( render!( templates::login_html, Some(Notification { kind: Kind::Error, message: format!("the user \"{}\" does not exist", &form.username) }) ) .unwrap(), )); } Err(_) => { return Ok(HttpResponse::InternalServerError().body( render!( templates::login_html, Some(Notification { kind: Kind::Error, message: "internal server error. please try again later".to_owned() }) ) .unwrap(), )); } } }