summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs83
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")