diff --git a/src/main.rs b/src/main.rs index d9a59eb..343f409 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,21 @@ use std::{ + error::Error, fmt::{Debug, Display}, net::SocketAddr, + ops::Range, }; use askama::Template; use axum::{ extract::{Form, Path}, http::StatusCode, - response::{IntoResponse, Response}, + response::{IntoResponse, Redirect, Response}, routing::get, Router, }; use serde::{Deserialize, Serialize}; use tower_sessions::{MemoryStore, Session, SessionManagerLayer}; +use unicode_segmentation::UnicodeSegmentation; #[macro_use] extern crate justerror; @@ -28,13 +31,60 @@ async fn get_signup() -> impl IntoResponse { } /// Receives the form with the user signup fields filled out. -async fn post_signup(session: Session, Form(form): Form) -> impl IntoResponse { - todo!() +async fn post_signup( + session: Session, + Form(form): Form, +) -> Result { + let username = form.username.trim(); + let password = form.password.trim(); + let verify = form.pw_verify.trim(); + + let name_len = username.graphemes(true).size_hint().1.unwrap(); + // we are not ascii exclusivists around here + if !(1..=20).contains(&name_len) { + return Err(CreateUserErrorKind::BadUsername.into()); + } + + if password != verify { + return Err(CreateUserErrorKind::PasswordMismatch.into()); + } + let pwlen = password.graphemes(true).size_hint().1.unwrap_or(0); + if !(4..=50).contains(&pwlen) { + return Err(CreateUserErrorKind::BadPassword.into()); + } + + // clean up the optionals + let displayname = validate_optional_length( + &form.displayname, + 0..100, + CreateUserErrorKind::BadDisplayname, + )?; + + let email = validate_optional_length(&form.email, 5..30, CreateUserErrorKind::BadEmail)?; + + let user = User { + username: username.to_string(), + displayname, + email, + password: password.to_string(), + pw_verify: verify.to_string(), + }; + + session.insert(SIGNUP_KEY, user).await.unwrap(); + + Ok(Redirect::to( + "https://buy.stripe.com/test_eVa6rrb7ygjNbwk000", + )) } /// Called from Stripe with the receipt of payment. async fn signup_success(session: Session, receipt: Option>) -> impl IntoResponse { - todo!() + let user: User = session.get(SIGNUP_KEY).await.unwrap().unwrap_or_default(); + if user != User::default() { + SignupSuccessPage(user).into_response() + } else { + SignupErrorPage("who you?".to_string()).into_response() + } } #[tokio::main] @@ -89,10 +139,27 @@ pub struct SignupForm { pub email: Option, pub password: String, pub pw_verify: String, - pub invitation: String, } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] +#[template(path = "signup.html")] +pub struct SignupPage { + pub username: String, + pub displayname: Option, + pub email: Option, + pub password: String, + pub pw_verify: String, +} + +#[derive(Debug, Clone, Template, Default, Deserialize, Serialize, PartialEq, Eq)] +#[template(path = "signup_success.html")] +pub struct SignupSuccessPage(pub User); + +#[derive(Debug, Clone, Template, Default, Deserialize, Serialize, PartialEq, Eq)] +#[template(path = "signup_error.html")] +pub struct SignupErrorPage(pub String); + +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct User { pub username: String, pub displayname: Option, @@ -145,12 +212,20 @@ where } } -#[derive(Debug, Default, Template, Deserialize, Serialize, PartialEq, Eq)] -#[template(path = "signup.html")] -pub struct SignupPage { - pub username: String, - pub displayname: Option, - pub email: Option, - pub password: String, - pub pw_verify: String, +pub(crate) fn validate_optional_length( + opt: &Option, + len_range: Range, + err: E, +) -> Result, E> { + if let Some(opt) = opt { + let opt = opt.trim(); + let len = opt.graphemes(true).size_hint().1.unwrap(); + if !len_range.contains(&len) { + Err(err) + } else { + Ok(Some(opt.to_string())) + } + } else { + Ok(None) + } } diff --git a/templates/signup_success.html b/templates/signup_success.html index 50a24a9..a95224c 100644 --- a/templates/signup_success.html +++ b/templates/signup_success.html @@ -7,11 +7,13 @@

You did it!

-

-{{ self.0 }} -

+
+

+ {{ self.0 }} +

- -

Now, head on over to the login page and get watchin'!

- + +

Now, head on over to the login page and get watchin'! +

+ {% endblock %}