validates form and checks that there's a valid session when you come back
This commit is contained in:
parent
a31b41cb9e
commit
d9d7e7d9c7
2 changed files with 97 additions and 20 deletions
103
src/main.rs
103
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<SignupForm>) -> impl IntoResponse {
|
||||
todo!()
|
||||
async fn post_signup(
|
||||
session: Session,
|
||||
Form(form): Form<SignupForm>,
|
||||
) -> Result<impl IntoResponse, CreateUserError> {
|
||||
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<Path<String>>) -> 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<String>,
|
||||
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<String>,
|
||||
pub email: Option<String>,
|
||||
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<String>,
|
||||
|
@ -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<String>,
|
||||
pub email: Option<String>,
|
||||
pub password: String,
|
||||
pub pw_verify: String,
|
||||
pub(crate) fn validate_optional_length<E: Error>(
|
||||
opt: &Option<String>,
|
||||
len_range: Range<usize>,
|
||||
err: E,
|
||||
) -> Result<Option<String>, 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
|
||||
<h1>You did it!</h1>
|
||||
|
||||
<div id="signup_success"><p>
|
||||
{{ self.0 }}
|
||||
</p>
|
||||
<div id="signup_success">
|
||||
<p>
|
||||
{{ self.0 }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>Now, head on over to <a href="/login">the login page</a> and get watchin'!</p>
|
||||
|
||||
|
||||
<p>Now, head on over to <a href="/login?redirect_to={{ self.0.username|escape }}">the login page</a> and get watchin'!
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue