diff --git a/src/api/posts.rs b/src/api/posts.rs index f29c402a..56dc657f 100644 --- a/src/api/posts.rs +++ b/src/api/posts.rs @@ -19,7 +19,7 @@ fn get(id: i32, conn: DbConn) -> Json { #[get("/posts")] fn list(conn: DbConn, uri: &Origin) -> Json { - let query: PostEndpoint = serde_qs::from_str(uri.query().unwrap_or("")).expect("Invalid query string"); + let query: PostEndpoint = serde_qs::from_str(uri.query().unwrap_or("")).expect("api::list: invalid query error"); let post = >::list(&*conn, query); Json(json!(post)) } diff --git a/src/inbox.rs b/src/inbox.rs index d70fed5d..831e9bb8 100644 --- a/src/inbox.rs +++ b/src/inbox.rs @@ -16,7 +16,7 @@ use plume_models::{ pub trait Inbox { fn received(&self, conn: &Connection, act: serde_json::Value) -> Result<(), Error> { - let actor_id = Id::new(act["actor"].as_str().unwrap_or_else(|| act["actor"]["id"].as_str().expect("No actor ID for incoming activity"))); + let actor_id = Id::new(act["actor"].as_str().unwrap_or_else(|| act["actor"]["id"].as_str().expect("Inbox::received: actor_id missing error"))); match act["type"].as_str() { Some(t) => { match t { @@ -47,7 +47,7 @@ pub trait Inbox { }, "Undo" => { let act: Undo = serde_json::from_value(act.clone())?; - match act.undo_props.object["type"].as_str().unwrap() { + match act.undo_props.object["type"].as_str().expect("Inbox::received: undo without original type error") { "Like" => { likes::Like::delete_id(act.undo_props.object_object::()?.object_props.id_string()?, conn); Ok(()) diff --git a/src/main.rs b/src/main.rs index 691f0c34..cdd38b6b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,7 +56,7 @@ fn init_pool() -> Option { } fn main() { - let pool = init_pool().expect("Couldn't intialize database pool"); + let pool = init_pool().expect("main: database pool initialization error"); rocket::ignite() .mount("/", routes![ routes::blogs::paginated_details, @@ -176,6 +176,6 @@ fn main() { ("/login".to_owned(), "/login".to_owned(), rocket::http::Method::Post), ("/users/new".to_owned(), "/users/new".to_owned(), rocket::http::Method::Post), ]) - .finalize().unwrap()) + .finalize().expect("main: csrf fairing creation error")) .launch(); } diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 829ff7c0..e18ebbb8 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -1,9 +1,9 @@ use activitypub::collection::OrderedCollection; use atom_syndication::{Entry, FeedBuilder}; use rocket::{ + http::ContentType, request::LenientForm, - response::{Redirect, Flash, content::Content}, - http::ContentType + response::{Redirect, Flash, content::Content} }; use rocket_contrib::Template; use serde_json; @@ -49,9 +49,9 @@ fn details(name: String, conn: DbConn, user: Option) -> Template { } #[get("/~/", rank = 1)] -fn activity_details(name: String, conn: DbConn, _ap: ApRequest) -> ActivityStream { - let blog = Blog::find_local(&*conn, name).unwrap(); - ActivityStream::new(blog.into_activity(&*conn)) +fn activity_details(name: String, conn: DbConn, _ap: ApRequest) -> Option> { + let blog = Blog::find_local(&*conn, name)?; + Some(ActivityStream::new(blog.into_activity(&*conn))) } #[get("/blogs/new")] @@ -130,22 +130,23 @@ fn create(conn: DbConn, data: LenientForm, user: User) -> Result/outbox")] -fn outbox(name: String, conn: DbConn) -> ActivityStream { - let blog = Blog::find_local(&*conn, name).unwrap(); - blog.outbox(&*conn) +fn outbox(name: String, conn: DbConn) -> Option> { + let blog = Blog::find_local(&*conn, name)?; + Some(blog.outbox(&*conn)) } #[get("/~//atom.xml")] -fn atom_feed(name: String, conn: DbConn) -> Content { - let blog = Blog::find_by_fqn(&*conn, name.clone()).expect("Unable to find blog"); +fn atom_feed(name: String, conn: DbConn) -> Option> { + let blog = Blog::find_by_fqn(&*conn, name.clone())?; let feed = FeedBuilder::default() .title(blog.title.clone()) - .id(Instance::get_local(&*conn).unwrap().compute_box("~", name, "atom.xml")) + .id(Instance::get_local(&*conn).expect("blogs::atom_feed: local instance not found error") + .compute_box("~", name, "atom.xml")) .entries(Post::get_recents_for_blog(&*conn, &blog, 15) .into_iter() .map(|p| super::post_to_atom(p, &*conn)) .collect::>()) .build() - .expect("Error building Atom feed"); - Content(ContentType::new("application", "atom+xml"), feed.to_string()) + .expect("blogs::atom_feed: feed creation error"); + Some(Content(ContentType::new("application", "atom+xml"), feed.to_string())) } diff --git a/src/routes/comments.rs b/src/routes/comments.rs index 17d49828..da88e556 100644 --- a/src/routes/comments.rs +++ b/src/routes/comments.rs @@ -28,9 +28,10 @@ struct NewCommentForm { } #[post("/~///comment", data = "")] -fn create(blog_name: String, slug: String, data: LenientForm, user: User, conn: DbConn, worker: State>>) -> Result { - let blog = Blog::find_by_fqn(&*conn, blog_name.clone()).unwrap(); - let post = Post::find_by_slug(&*conn, slug.clone(), blog.id).unwrap(); +fn create(blog_name: String, slug: String, data: LenientForm, user: User, conn: DbConn, worker: State>>) + -> Result> { + let blog = Blog::find_by_fqn(&*conn, blog_name.clone()).ok_or(None)?; + let post = Post::find_by_slug(&*conn, slug.clone(), blog.id).ok_or(None)?; let form = data.get(); form.validate() .map(|_| { @@ -63,7 +64,7 @@ fn create(blog_name: String, slug: String, data: LenientForm, us let comments = Comment::list_by_post(&*conn, post.id); let comms = comments.clone(); - Template::render("posts/details", json!({ + Some(Template::render("posts/details", json!({ "author": post.get_authors(&*conn)[0].to_json(&*conn), "post": post, "blog": blog, @@ -74,10 +75,10 @@ fn create(blog_name: String, slug: String, data: LenientForm, us "has_reshared": user.has_reshared(&*conn, &post), "account": user.to_json(&*conn), "date": &post.creation_date.timestamp(), - "previous": form.responding_to.map(|r| Comment::get(&*conn, r).expect("Error retrieving previous comment").to_json(&*conn, &vec![])), + "previous": form.responding_to.and_then(|r| Comment::get(&*conn, r)).map(|r| r.to_json(&*conn, &vec![])), "user_fqn": user.get_fqn(&*conn), "errors": errors - })) + }))) }) } diff --git a/src/routes/errors.rs b/src/routes/errors.rs index 5f9f3f5c..8ddf0a02 100644 --- a/src/routes/errors.rs +++ b/src/routes/errors.rs @@ -6,21 +6,21 @@ use plume_models::users::User; #[catch(404)] fn not_found(req: &Request) -> Template { - let conn = req.guard::().expect("404: DbConn error"); + let conn = req.guard::().succeeded(); let user = User::from_request(req).succeeded(); Template::render("errors/404", json!({ "error_message": "Page not found", - "account": user.map(|u| u.to_json(&*conn)) + "account": user.and_then(|u| conn.map(|conn| u.to_json(&*conn))) })) } #[catch(500)] fn server_error(req: &Request) -> Template { - let conn = req.guard::().expect("500: DbConn error"); + let conn = req.guard::().succeeded(); let user = User::from_request(req).succeeded(); Template::render("errors/500", json!({ "error_message": "Server error", - "account": user.map(|u| u.to_json(&*conn)) + "account": user.and_then(|u| conn.map(|conn| u.to_json(&*conn))) })) } diff --git a/src/routes/instance.rs b/src/routes/instance.rs index 35f85895..2a07e464 100644 --- a/src/routes/instance.rs +++ b/src/routes/instance.rs @@ -1,5 +1,5 @@ use gettextrs::gettext; -use rocket::{request::LenientForm, response::Redirect}; +use rocket::{request::LenientForm, response::{status, Redirect}}; use rocket_contrib::{Json, Template}; use serde_json; use validator::{Validate}; @@ -52,7 +52,7 @@ fn index(conn: DbConn, user: Option) -> Template { #[get("/local?")] fn paginated_local(conn: DbConn, user: Option, page: Page) -> Template { - let instance = Instance::get_local(&*conn).unwrap(); + let instance = Instance::get_local(&*conn).expect("instance::paginated_local: local instance not found error"); let articles = Post::get_instance_page(&*conn, instance.id, page.limits()); Template::render("instance/local", json!({ "account": user.map(|u| u.to_json(&*conn)), @@ -129,7 +129,7 @@ fn update_settings(conn: DbConn, admin: Admin, form: LenientForm Redirect { } #[post("/inbox", data = "")] -fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> String { - let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap(); +fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> Result> { + let act: serde_json::Value = serde_json::from_str(&data[..]).expect("instance::shared_inbox: deserialization error"); let activity = act.clone(); let actor_id = activity["actor"].as_str() - .unwrap_or_else(|| activity["actor"]["id"].as_str().expect("No actor ID for incoming activity, blocks by panicking")); + .or_else(|| activity["actor"]["id"].as_str()).ok_or(status::BadRequest(Some("Missing actor id for activity")))?; - let actor = User::from_url(&conn, actor_id.to_owned()).unwrap(); + let actor = User::from_url(&conn, actor_id.to_owned()).expect("instance::shared_inbox: user error"); if !verify_http_headers(&actor, headers.0.clone(), data).is_secure() && !act.clone().verify(&actor) { println!("Rejected invalid activity supposedly from {}, with headers {:?}", actor.username, headers.0); - return "invalid signature".to_owned(); + return Err(status::BadRequest(Some("Invalid signature"))); } if Instance::is_blocked(&*conn, actor_id.to_string()) { - return String::new(); + return Ok(String::new()); } - let instance = Instance::get_local(&*conn).unwrap(); - match instance.received(&*conn, act) { + let instance = Instance::get_local(&*conn).expect("instance::shared_inbox: local instance not found error"); + Ok(match instance.received(&*conn, act) { Ok(_) => String::new(), Err(e) => { println!("Shared inbox error: {}\n{}", e.as_fail(), e.backtrace()); format!("Error: {}", e.as_fail()) } - } + }) } #[get("/nodeinfo")] @@ -263,7 +263,7 @@ fn about(user: Option, conn: DbConn) -> Template { #[get("/manifest.json")] fn web_manifest(conn: DbConn) -> Json { - let instance = Instance::get_local(&*conn).unwrap(); + let instance = Instance::get_local(&*conn).expect("instance::web_manifest: local instance not found error"); Json(json!({ "name": &instance.name, "description": &instance.short_description, diff --git a/src/routes/likes.rs b/src/routes/likes.rs index 699ac7f4..19d18b81 100644 --- a/src/routes/likes.rs +++ b/src/routes/likes.rs @@ -12,9 +12,9 @@ use plume_models::{ }; #[post("/~///like")] -fn create(blog: String, slug: String, user: User, conn: DbConn, worker: State>>) -> Redirect { - let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap(); - let post = Post::find_by_slug(&*conn, slug.clone(), b.id).unwrap(); +fn create(blog: String, slug: String, user: User, conn: DbConn, worker: State>>) -> Option { + let b = Blog::find_by_fqn(&*conn, blog.clone())?; + let post = Post::find_by_slug(&*conn, slug.clone(), b.id)?; if !user.has_liked(&*conn, &post) { let like = likes::Like::insert(&*conn, likes::NewLike { @@ -29,13 +29,13 @@ fn create(blog: String, slug: String, user: User, conn: DbConn, worker: State//like", rank = 2)] diff --git a/src/routes/medias.rs b/src/routes/medias.rs index 87b00e91..c2092e05 100644 --- a/src/routes/medias.rs +++ b/src/routes/medias.rs @@ -1,6 +1,6 @@ use guid_create::GUID; use multipart::server::{Multipart, save::{SavedData, SaveResult}}; -use rocket::{Data, http::ContentType, response::Redirect}; +use rocket::{Data, http::ContentType, response::{Redirect, status}}; use rocket_contrib::Template; use serde_json; use std::fs; @@ -25,30 +25,27 @@ fn new(user: User, conn: DbConn) -> Template { } #[post("/medias/new", data = "")] -fn upload(user: User, data: Data, ct: &ContentType, conn: DbConn) -> Redirect { +fn upload(user: User, data: Data, ct: &ContentType, conn: DbConn) -> Result> { if ct.is_form_data() { - let (_, boundary) = ct.params().find(|&(k, _)| k == "boundary").expect("No boundary"); + let (_, boundary) = ct.params().find(|&(k, _)| k == "boundary").ok_or_else(|| status::BadRequest(Some("No boundary")))?; match Multipart::with_body(data.open(), boundary).save().temp() { SaveResult::Full(entries) => { let fields = entries.fields; - let filename = fields.get(&"file".to_string()).unwrap().into_iter().next().unwrap().headers - .filename.clone() - .unwrap_or("x.png".to_string()); // PNG by default - let ext = filename.rsplitn(2, ".") - .next() - .unwrap(); + let filename = fields.get(&"file".to_string()).and_then(|v| v.into_iter().next()) + .ok_or_else(|| status::BadRequest(Some("No file uploaded")))?.headers + .filename.clone(); + let ext = filename.and_then(|f| f.rsplit('.').next().map(|ext| ext.to_owned())) + .unwrap_or("png".to_owned()); let dest = format!("static/media/{}.{}", GUID::rand().to_string(), ext); - if let SavedData::Bytes(ref bytes) = fields[&"file".to_string()][0].data { - fs::write(&dest, bytes).expect("Couldn't save upload"); - } else { - if let SavedData::File(ref path, _) = fields[&"file".to_string()][0].data { - fs::copy(path, &dest).expect("Couldn't copy temp upload"); - } else { - println!("not file"); - return Redirect::to(uri!(new)); + match fields[&"file".to_string()][0].data { + SavedData::Bytes(ref bytes) => fs::write(&dest, bytes).expect("media::upload: Couldn't save upload"), + SavedData::File(ref path, _) => {fs::copy(path, &dest).expect("media::upload: Couldn't copy upload");}, + _ => { + println!("not a file"); + return Ok(Redirect::to(uri!(new))); } } @@ -67,16 +64,16 @@ fn upload(user: User, data: Data, ct: &ContentType, conn: DbConn) -> Redirect { owner_id: user.id }); println!("ok"); - Redirect::to(uri!(details: id = media.id)) + Ok(Redirect::to(uri!(details: id = media.id))) }, SaveResult::Partial(_, _) | SaveResult::Error(_) => { println!("partial err"); - Redirect::to(uri!(new)) + Ok(Redirect::to(uri!(new))) } } } else { println!("not form data"); - Redirect::to(uri!(new)) + Ok(Redirect::to(uri!(new))) } } @@ -98,15 +95,15 @@ fn details(id: i32, user: User, conn: DbConn) -> Template { } #[post("/medias//delete")] -fn delete(id: i32, _user: User, conn: DbConn) -> Redirect { - let media = Media::get(&*conn, id).expect("Media to delete not found"); +fn delete(id: i32, _user: User, conn: DbConn) -> Option { + let media = Media::get(&*conn, id)?; media.delete(&*conn); - Redirect::to(uri!(list)) + Some(Redirect::to(uri!(list))) } #[post("/medias//avatar")] -fn set_avatar(id: i32, user: User, conn: DbConn) -> Redirect { - let media = Media::get(&*conn, id).expect("Media to delete not found"); +fn set_avatar(id: i32, user: User, conn: DbConn) -> Option { + let media = Media::get(&*conn, id)?; user.set_avatar(&*conn, media.id); - Redirect::to(uri!(details: id = id)) + Some(Redirect::to(uri!(details: id = id))) } diff --git a/src/routes/posts.rs b/src/routes/posts.rs index f642946a..3a81a328 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -58,7 +58,8 @@ fn details_response(blog: String, slug: String, conn: DbConn, user: Option "has_reshared": user.clone().map(|u| u.has_reshared(&*conn, &post)).unwrap_or(false), "account": &user.clone().map(|u| u.to_json(&*conn)), "date": &post.creation_date.timestamp(), - "previous": query.and_then(|q| q.responding_to.map(|r| Comment::get(&*conn, r).expect("Error retrieving previous comment").to_json(&*conn, &vec![]))), + "previous": query.and_then(|q| q.responding_to.map(|r| Comment::get(&*conn, r) + .expect("posts::details_reponse: Error retrieving previous comment").to_json(&*conn, &vec![]))), "user_fqn": user.clone().map(|u| u.get_fqn(&*conn)).unwrap_or(String::new()), "is_author": user.clone().map(|u| post.get_authors(&*conn).into_iter().any(|a| u.id == a.id)).unwrap_or(false), "is_following": user.map(|u| u.is_following(&*conn, post.get_authors(&*conn)[0].id)).unwrap_or(false) @@ -73,13 +74,13 @@ fn details_response(blog: String, slug: String, conn: DbConn, user: Option } #[get("/~//", rank = 3)] -fn activity_details(blog: String, slug: String, conn: DbConn, _ap: ApRequest) -> Result, String> { - let blog = Blog::find_by_fqn(&*conn, blog).unwrap(); - let post = Post::find_by_slug(&*conn, slug, blog.id).unwrap(); +fn activity_details(blog: String, slug: String, conn: DbConn, _ap: ApRequest) -> Result, Option> { + let blog = Blog::find_by_fqn(&*conn, blog).ok_or(None)?; + let post = Post::find_by_slug(&*conn, slug, blog.id).ok_or(None)?; if post.published { Ok(ActivityStream::new(post.into_activity(&*conn))) } else { - Err(String::from("Not published yet.")) + Err(Some(String::from("Not published yet."))) } } @@ -92,42 +93,42 @@ fn new_auth(blog: String) -> Flash { } #[get("/~//new", rank = 1)] -fn new(blog: String, user: User, conn: DbConn) -> Template { - let b = Blog::find_by_fqn(&*conn, blog.to_string()).unwrap(); +fn new(blog: String, user: User, conn: DbConn) -> Option