diff --git a/Cargo.lock b/Cargo.lock index 2acf013..dbacf7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -851,9 +851,9 @@ dependencies = [ [[package]] name = "funty" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" @@ -1200,13 +1200,13 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lexical-core" -version = "0.7.5" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" dependencies = [ "arrayvec", "bitflags", - "cfg-if 1.0.0", + "cfg-if 0.1.10", "ryu", "static_assertions", ] diff --git a/rustfmt.toml b/rustfmt.toml index f5f51de..3477693 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ edition = "2018" tab_spaces = 2 hard_tabs = true -max_width = 150 \ No newline at end of file +max_width = 175 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index be68803..15a19d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,3 @@ -// Import Crates -// use askama::filters::format; -use tide::{Middleware, Next, Request, Response, utils::{After, async_trait}}; - // Reference local files mod post; mod proxy; @@ -11,6 +7,13 @@ mod subreddit; mod user; mod utils; +// Import Crates +use tide::{ + utils::{async_trait, After}, + Middleware, Next, Request, Response, +}; +use utils::{error, redirect}; + // Build middleware struct HttpsRedirect(HttpsOnly); struct NormalizePath; @@ -28,7 +31,7 @@ where let mut secured = request.url().to_owned(); secured.set_scheme("https").unwrap_or_default(); - Ok(Response::builder(302).header("Location", secured.to_string()).build()) + Ok(redirect(secured.to_string())) } else { Ok(next.run(request).await) } @@ -48,12 +51,7 @@ impl Middleware for NormalizePath { // Create Services async fn style(_req: Request<()>) -> tide::Result { - Ok( - Response::builder(200) - .content_type("text/css") - .body(include_str!("../static/style.css")) - .build(), - ) + Ok(Response::builder(200).content_type("text/css").body(include_str!("../static/style.css")).build()) } // Required for creating a PWA @@ -68,12 +66,7 @@ async fn manifest(_req: Request<()>) -> tide::Result { // Required for the manifest to be valid async fn pwa_logo(_req: Request<()>) -> tide::Result { - Ok( - Response::builder(200) - .content_type("image/png") - .body(include_bytes!("../static/logo.png").as_ref()) - .build(), - ) + Ok(Response::builder(200).content_type("image/png").body(include_bytes!("../static/logo.png").as_ref()).build()) } // Required for iOS App Icons @@ -206,12 +199,12 @@ async fn main() -> tide::Result<()> { Ok("best") | Ok("hot") | Ok("new") | Ok("top") | Ok("rising") | Ok("controversial") => subreddit::page(req).await, // Short link for post Ok(id) if id.len() > 4 && id.len() < 7 => post::item(req).await, - _ => utils::error("Nothing here".to_string()).await + _ => error("Nothing here".to_string()).await, } }); // Default service in case no routes match - app.at("*").get(|_| utils::error("Nothing here".to_string())); + app.at("*").get(|_| error("Nothing here".to_string())); app.listen(address).await?; Ok(()) diff --git a/src/post.rs b/src/post.rs index 991b508..90caeaf 100644 --- a/src/post.rs +++ b/src/post.rs @@ -30,18 +30,13 @@ pub async fn item(req: Request<()>) -> tide::Result { // If there's no sort query but there's a default sort, set sort to default_sort if sort.is_empty() && !default_sort.is_empty() { sort = default_sort; - path = format!( - "{}.json?{}&sort={}&raw_json=1", - req.url().path(), - req.url().query().unwrap_or_default(), - sort - ); + path = format!("{}.json?{}&sort={}&raw_json=1", req.url().path(), req.url().query().unwrap_or_default(), sort); } // Log the post ID being fetched in debug mode #[cfg(debug_assertions)] dbg!(req.param("id").unwrap_or("")); - + let single_thread = &req.param("comment_id").is_ok(); let highlighted_comment = &req.param("comment_id").unwrap_or_default(); @@ -160,13 +155,13 @@ async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: } else { Vec::new() }; - + let parent_kind_and_id = val(&comment, "parent_id"); let parent_info = parent_kind_and_id.split("_").collect::>(); - + let id = val(&comment, "id"); let highlighted = id == highlighted_comment; - + comments.push(Comment { id, kind: comment["kind"].as_str().unwrap_or_default().to_string(), diff --git a/src/settings.rs b/src/settings.rs index d68e969..59a7ad8 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,7 +1,7 @@ // CRATES -use crate::utils::{prefs, template, Preferences}; +use crate::utils::{prefs, redirect, template, Preferences}; use askama::Template; -use tide::{http::Cookie, Request, Response}; +use tide::{http::Cookie, Request}; use time::{Duration, OffsetDateTime}; // STRUCTS @@ -35,11 +35,7 @@ pub async fn get(req: Request<()>) -> tide::Result { pub async fn set(mut req: Request<()>) -> tide::Result { let form: SettingsForm = req.body_form().await.unwrap_or_default(); - let mut res = Response::builder(302) - .content_type("text/html") - .header("Location", "/settings") - .body(r#"Redirecting to settings..."#) - .build(); + let mut res = redirect("/settings".to_string()); let names = vec!["theme", "front_page", "layout", "wide", "comment_sort", "show_nsfw"]; let values = vec![form.theme, form.front_page, form.layout, form.wide, form.comment_sort, form.show_nsfw]; @@ -60,22 +56,16 @@ pub async fn set(mut req: Request<()>) -> tide::Result { Ok(res) } - // Set cookies using response "Set-Cookie" header pub async fn restore(req: Request<()>) -> tide::Result { let form: SettingsForm = req.query()?; - let path = match form.redirect { Some(value) => format!("/{}/", value), - None => "/".to_string() + None => "/".to_string(), }; - let mut res = Response::builder(302) - .content_type("text/html") - .header("Location", path.to_owned()) - .body(format!("Redirecting to {0}...", path)) - .build(); + let mut res = redirect(path); let names = vec!["theme", "front_page", "layout", "wide", "comment_sort", "show_nsfw", "subscriptions"]; let values = vec![form.theme, form.front_page, form.layout, form.wide, form.comment_sort, form.show_nsfw, form.subscriptions]; diff --git a/src/subreddit.rs b/src/subreddit.rs index 6a9815f..473ec29 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -1,7 +1,7 @@ // CRATES use crate::utils::*; use askama::Template; -use tide::{http::Cookie, Request, Response}; +use tide::{http::Cookie, Request}; use time::{Duration, OffsetDateTime}; // STRUCTS @@ -31,18 +31,15 @@ pub async fn page(req: Request<()>) -> tide::Result { let front_page = cookie(&req, "front_page"); let sort = req.param("sort").unwrap_or_else(|_| req.param("id").unwrap_or("hot")).to_string(); - let sub = req - .param("sub") - .map(String::from) - .unwrap_or(if front_page == "default" || front_page.is_empty() { - if subscribed.is_empty() { - "popular".to_string() - } else { - subscribed.to_owned() - } + let sub = req.param("sub").map(String::from).unwrap_or(if front_page == "default" || front_page.is_empty() { + if subscribed.is_empty() { + "popular".to_string() } else { - front_page.to_owned() - }); + subscribed.to_owned() + } + } else { + front_page.to_owned() + }); let path = format!("/r/{}/{}.json?{}&raw_json=1", sub, sort, req.url().query().unwrap_or_default()); @@ -112,11 +109,7 @@ pub async fn subscriptions(req: Request<()>) -> tide::Result { format!("/r/{}", sub) }; - let mut res = Response::builder(302) - .content_type("text/html") - .header("Location", path.to_owned()) - .body(format!("Redirecting to {0}...", path)) - .build(); + let mut res = redirect(path); // Delete cookie if empty, else set if sub_list.is_empty() { @@ -165,14 +158,8 @@ async fn subreddit(sub: &str) -> Result { let active: i64 = res["data"]["accounts_active"].as_u64().unwrap_or_default() as i64; // Fetch subreddit icon either from the community_icon or icon_img value - let community_icon: &str = res["data"]["community_icon"] - .as_str() - .map_or("", |s| s.split('?').collect::>()[0]); - let icon = if community_icon.is_empty() { - val(&res, "icon_img") - } else { - community_icon.to_string() - }; + let community_icon: &str = res["data"]["community_icon"].as_str().map_or("", |s| s.split('?').collect::>()[0]); + let icon = if community_icon.is_empty() { val(&res, "icon_img") } else { community_icon.to_string() }; let sub = Subreddit { name: val(&res, "display_name"), diff --git a/src/utils.rs b/src/utils.rs index 451b0aa..555f0cf 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -162,24 +162,14 @@ pub fn prefs(req: Request<()>) -> Preferences { wide: cookie(&req, "wide"), show_nsfw: cookie(&req, "show_nsfw"), comment_sort: cookie(&req, "comment_sort"), - subscriptions: cookie(&req, "subscriptions") - .split('+') - .map(String::from) - .filter(|s| !s.is_empty()) - .collect(), + subscriptions: cookie(&req, "subscriptions").split('+').map(String::from).filter(|s| !s.is_empty()).collect(), } } // Grab a query param from a url pub fn param(path: &str, value: &str) -> String { match Url::parse(format!("https://libredd.it/{}", path).as_str()) { - Ok(url) => url - .query_pairs() - .into_owned() - .collect::>() - .get(value) - .unwrap_or(&String::new()) - .to_owned(), + Ok(url) => url.query_pairs().into_owned().collect::>().get(value).unwrap_or(&String::new()).to_owned(), _ => String::new(), } } @@ -226,8 +216,8 @@ pub async fn media(data: &Value) -> (String, Media, Vec) { } else if data["secure_media"]["reddit_video"]["fallback_url"].is_string() { post_type = "video"; format_url(data["secure_media"]["reddit_video"]["fallback_url"].as_str().unwrap_or_default()) - // Handle images, whether GIFs or pics } else if data["post_hint"].as_str().unwrap_or("") == "image" { + // Handle images, whether GIFs or pics let preview = data["preview"]["images"][0].clone(); let mp4 = &preview["variants"]["mp4"]; if mp4.is_object() { @@ -438,13 +428,16 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec tide::Result { - Ok( - Response::builder(200) - .content_type("text/html") - .body(f.render().unwrap_or_default()) - .build(), - ) +pub fn template(t: impl Template) -> tide::Result { + Ok(Response::builder(200).content_type("text/html").body(t.render().unwrap_or_default()).build()) +} + +pub fn redirect(path: String) -> Response { + Response::builder(302) + .content_type("text/html") + .header("Location", &path) + .body(format!("Redirecting to {0}...", path)) + .build() } pub async fn error(msg: String) -> tide::Result {