From 2407c1a4a55d17817b31f7ca5cac9d68b27f536c Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Mon, 11 Dec 2023 06:02:00 +0000 Subject: implement signup --- migrations/20231003193749_pinussy.sql | 6 +-- src/main.rs | 83 ++++++++++++++++++++++++++++++++--- templates/base.rs.html | 10 ++++- templates/login.rs.html | 7 +-- templates/signup.rs.html | 7 +-- templates/users.rs.html | 2 +- 6 files changed, 94 insertions(+), 21 deletions(-) diff --git a/migrations/20231003193749_pinussy.sql b/migrations/20231003193749_pinussy.sql index 24f3aa1..cba545e 100644 --- a/migrations/20231003193749_pinussy.sql +++ b/migrations/20231003193749_pinussy.sql @@ -4,7 +4,7 @@ create type file_type as enum ('image', 'video', 'audio', 'text', 'document', 's create table users ( id integer primary key generated always as identity, username varchar(32) not null, - unique(id, username), + unique(username), password varchar(128) not null, email varchar(128), bio text, @@ -23,7 +23,6 @@ create table sessions ( create table boards ( id integer primary key generated always as identity, idname varchar(256), - unique(id, idname), name varchar(256), description text, privacy privacy @@ -40,7 +39,6 @@ create table board_ownership ( create table pins ( id integer primary key generated always as identity, idname varchar(256), - unique(id, idname), subject varchar(256), notes text, privacy privacy @@ -65,7 +63,6 @@ create table pins_boards ( create table sources ( id integer primary key generated always as identity, idname varchar(256), - unique(id, idname), title varchar(256), author varchar(256), url varchar(256), @@ -85,7 +82,6 @@ create table pin_sources ( create table files ( id integer primary key generated always as identity, idname varchar(256), - unique(id, idname), thumbnail varchar(256), path varchar(256) not null, title varchar(256), 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") diff --git a/templates/base.rs.html b/templates/base.rs.html index 5b1a324..64a8d4e 100644 --- a/templates/base.rs.html +++ b/templates/base.rs.html @@ -1,6 +1,7 @@ @use super::statics::*; +@use crate::Notification; -@(authenticated: bool, body: Content) +@(authenticated: bool, notification: Option, body: Content) @@ -15,11 +16,16 @@ + @if let Some(notification) = notification { +
@notification.message
+ } @:body() diff --git a/templates/login.rs.html b/templates/login.rs.html index 349263c..c87866c 100644 --- a/templates/login.rs.html +++ b/templates/login.rs.html @@ -1,8 +1,9 @@ @use super::base_html; +@use crate::Notification; -@() +@(notification: Option) -@:base_html(false, { +@:base_html(false, None, {
@@ -12,4 +13,4 @@
-}) \ No newline at end of file +}) diff --git a/templates/signup.rs.html b/templates/signup.rs.html index 354dae6..a482fc2 100644 --- a/templates/signup.rs.html +++ b/templates/signup.rs.html @@ -1,8 +1,9 @@ @use super::base_html; +@use crate::Notification; -@() +@(notification: Option) -@:base_html(false, { +@:base_html(false, notification, {
@@ -10,4 +11,4 @@
-}) \ No newline at end of file +}) diff --git a/templates/users.rs.html b/templates/users.rs.html index 9b9be30..ab1ab0f 100644 --- a/templates/users.rs.html +++ b/templates/users.rs.html @@ -3,7 +3,7 @@ @(users: Vec) -@:base_html(false, { +@:base_html(false, None, {
    @for user in users {
  • @user.username
  • -- cgit