Actually validate forms
This commit is contained in:
parent
c81bb9ec25
commit
153400959c
@ -1,4 +1,4 @@
|
||||
-- Your SQL goes here
|
||||
l-- Your SQL goes here
|
||||
CREATE TABLE instances (
|
||||
id SERIAL PRIMARY KEY,
|
||||
local_domain VARCHAR NOT NULL,
|
||||
|
@ -5,7 +5,7 @@ use rocket::{
|
||||
};
|
||||
use rocket_contrib::Template;
|
||||
use serde_json;
|
||||
use validator::{Validate, ValidationError};
|
||||
use validator::{Validate, ValidationError, ValidationErrors};
|
||||
|
||||
use plume_common::activity_pub::ActivityStream;
|
||||
use plume_common::utils;
|
||||
@ -66,15 +66,22 @@ fn valid_slug(title: &str) -> Result<(), ValidationError> {
|
||||
}
|
||||
|
||||
#[post("/blogs/new", data = "<data>")]
|
||||
fn create(conn: DbConn, data: LenientForm<NewBlogForm>, user: User) -> Redirect {
|
||||
fn create(conn: DbConn, data: LenientForm<NewBlogForm>, user: User) -> Result<Redirect, Template> {
|
||||
let form = data.get();
|
||||
let slug = utils::make_actor_id(form.title.to_string());
|
||||
let slug_taken_err = Blog::find_local(&*conn, slug.clone()).ok_or(ValidationError::new("existing_slug"));
|
||||
|
||||
if Blog::find_local(&*conn, slug.clone()).is_some() || slug.len() == 0 {
|
||||
Redirect::to(uri!(new))
|
||||
} else {
|
||||
let mut errors = match form.validate() {
|
||||
Ok(_) => ValidationErrors::new(),
|
||||
Err(e) => e
|
||||
};
|
||||
if let Err(e) = slug_taken_err {
|
||||
errors.add("title", e)
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
let blog = Blog::insert(&*conn, NewBlog::new_local(
|
||||
slug.to_string(),
|
||||
slug.clone(),
|
||||
form.title.to_string(),
|
||||
String::from(""),
|
||||
Instance::local_id(&*conn)
|
||||
@ -87,7 +94,12 @@ fn create(conn: DbConn, data: LenientForm<NewBlogForm>, user: User) -> Redirect
|
||||
is_owner: true
|
||||
});
|
||||
|
||||
Redirect::to(uri!(details: name = slug))
|
||||
Ok(Redirect::to(uri!(details: name = slug.clone())))
|
||||
} else {
|
||||
Err(Template::render("blogs/new", json!({
|
||||
"account": user,
|
||||
"errors": errors.inner()
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use rocket::{
|
||||
request::LenientForm,
|
||||
response::Redirect
|
||||
};
|
||||
use rocket_contrib::Template;
|
||||
use serde_json;
|
||||
use validator::Validate;
|
||||
|
||||
@ -24,22 +25,44 @@ struct NewCommentForm {
|
||||
}
|
||||
|
||||
#[post("/~/<blog_name>/<slug>/comment", data = "<data>")]
|
||||
fn create(blog_name: String, slug: String, data: LenientForm<NewCommentForm>, user: User, conn: DbConn) -> Redirect {
|
||||
fn create(blog_name: String, slug: String, data: LenientForm<NewCommentForm>, user: User, conn: DbConn) -> Result<Redirect, Template> {
|
||||
let blog = Blog::find_by_fqn(&*conn, blog_name.clone()).unwrap();
|
||||
let post = Post::find_by_slug(&*conn, slug.clone(), blog.id).unwrap();
|
||||
let form = data.get();
|
||||
form.validate()
|
||||
.map(|_| {
|
||||
let (new_comment, id) = NewComment::build()
|
||||
.content(form.content.clone())
|
||||
.in_response_to_id(form.responding_to.clone())
|
||||
.post(post.clone())
|
||||
.author(user.clone())
|
||||
.create(&*conn);
|
||||
|
||||
let (new_comment, id) = NewComment::build()
|
||||
.content(form.content.clone())
|
||||
.in_response_to_id(form.responding_to.clone())
|
||||
.post(post)
|
||||
.author(user.clone())
|
||||
.create(&*conn);
|
||||
let instance = Instance::get_local(&*conn).unwrap();
|
||||
instance.received(&*conn, serde_json::to_value(new_comment.clone()).expect("JSON serialization error"))
|
||||
.expect("We are not compatible with ourselve: local broadcast failed (new comment)");
|
||||
broadcast(&user, new_comment, user.get_followers(&*conn));
|
||||
|
||||
let instance = Instance::get_local(&*conn).unwrap();
|
||||
instance.received(&*conn, serde_json::to_value(new_comment.clone()).expect("JSON serialization error"))
|
||||
.expect("We are not compatible with ourselve: local broadcast failed (new comment)");
|
||||
broadcast(&user, new_comment, user.get_followers(&*conn));
|
||||
Redirect::to(format!("/~/{}/{}/#comment-{}", blog_name, slug, id))
|
||||
})
|
||||
.map_err(|errors| {
|
||||
// TODO: de-duplicate this code
|
||||
let comments = Comment::list_by_post(&*conn, post.id);
|
||||
|
||||
Redirect::to(format!("/~/{}/{}/#comment-{}", blog_name, slug, id))
|
||||
Template::render("posts/details", json!({
|
||||
"author": post.get_authors(&*conn)[0].to_json(&*conn),
|
||||
"post": post,
|
||||
"blog": blog,
|
||||
"comments": comments.into_iter().map(|c| c.to_json(&*conn)).collect::<Vec<serde_json::Value>>(),
|
||||
"n_likes": post.get_likes(&*conn).len(),
|
||||
"has_liked": user.has_liked(&*conn, &post),
|
||||
"n_reshares": post.get_reshares(&*conn).len(),
|
||||
"has_reshared": user.has_reshared(&*conn, &post),
|
||||
"account": user,
|
||||
"date": &post.creation_date.timestamp(),
|
||||
"previous": form.responding_to.map(|r| Comment::get(&*conn, r).expect("Error retrieving previous comment").to_json(&*conn)),
|
||||
"user_fqn": user.get_fqn(&*conn),
|
||||
"errors": errors
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use rocket::request::LenientForm;
|
||||
use rocket::response::{Redirect, Flash};
|
||||
use rocket_contrib::Template;
|
||||
use serde_json;
|
||||
use validator::{Validate, ValidationError};
|
||||
use validator::{Validate, ValidationError, ValidationErrors};
|
||||
|
||||
use plume_common::activity_pub::{broadcast, ActivityStream};
|
||||
use plume_common::utils;
|
||||
@ -94,22 +94,32 @@ fn valid_slug(title: &str) -> Result<(), ValidationError> {
|
||||
let slug = title.to_string().to_kebab_case();
|
||||
if slug.len() == 0 {
|
||||
Err(ValidationError::new("empty_slug"))
|
||||
} else if slug == "new" {
|
||||
Err(ValidationError::new("invalid_slug"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/~/<blog_name>/new", data = "<data>")]
|
||||
fn create(blog_name: String, data: LenientForm<NewPostForm>, user: User, conn: DbConn) -> Redirect {
|
||||
fn create(blog_name: String, data: LenientForm<NewPostForm>, user: User, conn: DbConn) -> Result<Redirect, Template> {
|
||||
let blog = Blog::find_by_fqn(&*conn, blog_name.to_string()).unwrap();
|
||||
let form = data.get();
|
||||
let slug = form.title.to_string().to_kebab_case();
|
||||
let slug_taken_err = Blog::find_local(&*conn, slug.clone()).ok_or(ValidationError::new("existing_slug"));
|
||||
|
||||
let mut errors = match form.validate() {
|
||||
Ok(_) => ValidationErrors::new(),
|
||||
Err(e) => e
|
||||
};
|
||||
if let Err(e) = slug_taken_err {
|
||||
errors.add("title", e)
|
||||
}
|
||||
|
||||
if !user.is_author_in(&*conn, blog.clone()) {
|
||||
Redirect::to(uri!(super::blogs::details: name = blog_name))
|
||||
} else {
|
||||
if slug == "new" || Post::find_by_slug(&*conn, slug.clone(), blog.id).is_some() {
|
||||
Redirect::to(uri!(new: blog = blog_name))
|
||||
if errors.is_empty() {
|
||||
if !user.is_author_in(&*conn, blog.clone()) {
|
||||
// actually it's not "Ok"…
|
||||
Ok(Redirect::to(uri!(super::blogs::details: name = blog_name)))
|
||||
} else {
|
||||
let (content, mentions) = utils::md_to_html(form.content.to_string().as_ref());
|
||||
|
||||
@ -135,7 +145,12 @@ fn create(blog_name: String, data: LenientForm<NewPostForm>, user: User, conn: D
|
||||
let act = post.create_activity(&*conn);
|
||||
broadcast(&user, act, user.get_followers(&*conn));
|
||||
|
||||
Redirect::to(uri!(details: blog = blog_name, slug = slug))
|
||||
Ok(Redirect::to(uri!(details: blog = blog_name, slug = slug)))
|
||||
}
|
||||
} else {
|
||||
Err(Template::render("posts/new", json!({
|
||||
"account": user,
|
||||
"errors": errors.inner()
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
use gettextrs::gettext;
|
||||
use rocket::{
|
||||
http::{Cookie, Cookies, uri::Uri},
|
||||
response::{Redirect, status::NotFound},
|
||||
response::Redirect,
|
||||
request::{LenientForm,FlashMessage}
|
||||
};
|
||||
use rocket_contrib::Template;
|
||||
use validator::{Validate, ValidationError};
|
||||
use validator::{Validate, ValidationError, ValidationErrors};
|
||||
|
||||
use plume_models::{
|
||||
db_conn::DbConn,
|
||||
@ -42,28 +41,33 @@ struct LoginForm {
|
||||
}
|
||||
|
||||
#[post("/login", data = "<data>")]
|
||||
fn create(conn: DbConn, data: LenientForm<LoginForm>, flash: Option<FlashMessage>, mut cookies: Cookies) -> Result<Redirect, NotFound<String>> {
|
||||
fn create(conn: DbConn, data: LenientForm<LoginForm>, flash: Option<FlashMessage>, mut cookies: Cookies) -> Result<Redirect, Template> {
|
||||
let form = data.get();
|
||||
let user = match User::find_by_email(&*conn, form.email_or_name.to_string()) {
|
||||
Some(usr) => Ok(usr),
|
||||
None => match User::find_local(&*conn, form.email_or_name.to_string()) {
|
||||
Some(usr) => Ok(usr),
|
||||
None => Err(gettext("Invalid username or password"))
|
||||
}
|
||||
let user = User::find_by_email(&*conn, form.email_or_name.to_string())
|
||||
.map(|u| Ok(u))
|
||||
.unwrap_or_else(|| User::find_local(&*conn, form.email_or_name.to_string()).map(|u| Ok(u)).unwrap_or(Err(())));
|
||||
|
||||
let mut errors = match form.validate() {
|
||||
Ok(_) => ValidationErrors::new(),
|
||||
Err(e) => e
|
||||
};
|
||||
match user {
|
||||
Ok(usr) => {
|
||||
if usr.auth(form.password.to_string()) {
|
||||
cookies.add_private(Cookie::new(AUTH_COOKIE, usr.id.to_string()));
|
||||
Ok(Redirect::to(Uri::new(flash
|
||||
.and_then(|f| if f.name() == "callback" { Some(f.msg().to_owned()) } else { None })
|
||||
.unwrap_or("/".to_owned()))
|
||||
))
|
||||
} else {
|
||||
Err(NotFound(gettext("Invalid username or password")))
|
||||
}
|
||||
},
|
||||
Err(e) => Err(NotFound(String::from(e)))
|
||||
if let Err(_) = user.clone() {
|
||||
errors.add("email_or_name", ValidationError::new("invalid_login"))
|
||||
} else if !user.clone().expect("User not found").auth(form.password.clone()) {
|
||||
errors.add("email_or_name", ValidationError::new("invalid_login"))
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
cookies.add_private(Cookie::new(AUTH_COOKIE, user.unwrap().id.to_string()));
|
||||
Ok(Redirect::to(Uri::new(flash
|
||||
.and_then(|f| if f.name() == "callback" { Some(f.msg().to_owned()) } else { None })
|
||||
.unwrap_or("/".to_owned()))
|
||||
))
|
||||
} else {
|
||||
Err(Template::render("session/login", json!({
|
||||
"account": user,
|
||||
"errors": errors.inner()
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,29 +180,24 @@ fn passwords_match(form: &NewUserForm) -> Result<(), ValidationError> {
|
||||
}
|
||||
|
||||
#[post("/users/new", data = "<data>")]
|
||||
fn create(conn: DbConn, data: LenientForm<NewUserForm>) -> Result<Redirect, String> {
|
||||
fn create(conn: DbConn, data: LenientForm<NewUserForm>) -> Result<Redirect, Template> {
|
||||
let form = data.get();
|
||||
|
||||
if form.username.clone().len() < 1 {
|
||||
Err(String::from("Username is required"))
|
||||
} else if form.email.clone().len() < 1 {
|
||||
Err(String::from("Email is required"))
|
||||
} else if form.password.clone().len() < 8 {
|
||||
Err(String::from("Password should be at least 8 characters long"))
|
||||
} else if form.password == form.password_confirmation {
|
||||
NewUser::new_local(
|
||||
&*conn,
|
||||
form.username.to_string(),
|
||||
form.username.to_string(),
|
||||
false,
|
||||
String::from(""),
|
||||
form.email.to_string(),
|
||||
User::hash_pass(form.password.to_string())
|
||||
).update_boxes(&*conn);
|
||||
Ok(Redirect::to(uri!(super::session::new)))
|
||||
} else {
|
||||
Err(String::from("Passwords don't match"))
|
||||
}
|
||||
form.validate()
|
||||
.map(|_| {
|
||||
NewUser::new_local(
|
||||
&*conn,
|
||||
form.username.to_string(),
|
||||
form.username.to_string(),
|
||||
false,
|
||||
String::from(""),
|
||||
form.email.to_string(),
|
||||
User::hash_pass(form.password.to_string())
|
||||
).update_boxes(&*conn);
|
||||
Redirect::to(uri!(super::session::new))
|
||||
})
|
||||
.map_err(|e| Template::render("users/new", json!({
|
||||
"errors": e.inner()
|
||||
})))
|
||||
}
|
||||
|
||||
#[get("/@/<name>/outbox")]
|
||||
|
Loading…
Reference in New Issue
Block a user