diff --git a/src/main.rs b/src/main.rs index 2eabf35..9fecc83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +// Global specifiers +#![forbid(unsafe_code)] +#![warn(clippy::pedantic, clippy::all)] + // Reference local files mod post; mod proxy; @@ -48,10 +52,10 @@ impl Middleware for NormalizePath { if path.ends_with('/') { Ok(next.run(request).await) } else { - let normalized = if query != "" { - format!("{}/?{}", path.replace("//", "/"), query) - } else { + let normalized = if query.is_empty() { format!("{}/", path.replace("//", "/")) + } else { + format!("{}/?{}", path.replace("//", "/"), query) }; Ok(redirect(normalized)) } diff --git a/src/post.rs b/src/post.rs index 4b413e1..e4d357c 100644 --- a/src/post.rs +++ b/src/post.rs @@ -1,5 +1,5 @@ // CRATES -use crate::utils::*; +use crate::utils::{Author, Comment, Flags, Flair, FlairPart, Media, Post, Preferences, cookie, error, format_num, format_url, param, request, rewrite_urls, template, time, val}; use tide::Request; use async_recursion::async_recursion; @@ -68,7 +68,7 @@ async fn parse_post(json: &serde_json::Value) -> Post { let post: &serde_json::Value = &json["data"]["children"][0]; // Grab UTC time as unix timestamp - let (rel_time, created) = time(post["data"]["created_utc"].as_f64().unwrap_or_default()); + let (rel_time, created) = time(post["data"]["created_utc"].as_i64().unwrap_or_default()); // Parse post score and upvote ratio let score = post["data"]["score"].as_i64().unwrap_or_default(); let ratio: f64 = post["data"]["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0; @@ -149,10 +149,10 @@ async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: let kind = comment["kind"].as_str().unwrap_or_default().to_string(); let data = &comment["data"]; - let unix_time = data["created_utc"].as_f64().unwrap_or_default(); + let unix_time = data["created_utc"].as_i64().unwrap_or_default(); let (rel_time, created) = time(unix_time); - let edited = match data["edited"].as_f64() { + let edited = match data["edited"].as_i64() { Some(stamp) => time(stamp), None => (String::new(), String::new()), }; @@ -196,7 +196,7 @@ async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: distinguished: val(&comment, "distinguished"), }, score: if data["score_hidden"].as_bool().unwrap_or_default() { - "•".to_string() + "\u{2022}".to_string() } else { format_num(score) }, diff --git a/src/proxy.rs b/src/proxy.rs index 5cff7cf..de53fb5 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -15,7 +15,7 @@ pub async fn handler(req: Request<()>, format: &str, params: Vec<&str>) -> tide: async fn request(url: String) -> tide::Result { match surf::get(url).await { Ok(res) => { - let content_length = res.header("Content-Length").map(|v| v.to_string()).unwrap_or_default(); + let content_length = res.header("Content-Length").map(std::string::ToString::to_string).unwrap_or_default(); let content_type = res.content_type().map(|m| m.to_string()).unwrap_or_default(); Ok( diff --git a/src/search.rs b/src/search.rs index bcfc32e..1d42336 100644 --- a/src/search.rs +++ b/src/search.rs @@ -84,7 +84,7 @@ async fn search_subreddits(q: &str) -> Vec { name: val(subreddit, "display_name_prefixed"), url: val(subreddit, "url"), description: val(subreddit, "public_description"), - subscribers: subreddit["data"]["subscribers"].as_u64().unwrap_or_default() as i64, + subscribers: subreddit["data"]["subscribers"].as_i64().unwrap_or_default(), }) .collect::>(), _ => Vec::new(), diff --git a/src/settings.rs b/src/settings.rs index a3af1a0..03056e2 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -13,7 +13,7 @@ struct SettingsTemplate { #[derive(serde::Deserialize, Default)] #[serde(default)] -pub struct SettingsForm { +pub struct Form { theme: Option, front_page: Option, layout: Option, @@ -33,7 +33,7 @@ pub async fn get(req: Request<()>) -> tide::Result { // Set cookies using response "Set-Cookie" header pub async fn set(mut req: Request<()>) -> tide::Result { - let form: SettingsForm = req.body_form().await.unwrap_or_default(); + let form: Form = req.body_form().await.unwrap_or_default(); let mut res = redirect("/settings".to_string()); @@ -58,7 +58,7 @@ pub async fn set(mut req: Request<()>) -> tide::Result { // Set cookies using response "Set-Cookie" header pub async fn restore(req: Request<()>) -> tide::Result { - let form: SettingsForm = req.query()?; + let form: Form = req.query()?; let path = match form.redirect { Some(value) => format!("/{}/", value), diff --git a/src/subreddit.rs b/src/subreddit.rs index a4bb24e..67ed4d4 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -1,5 +1,5 @@ // CRATES -use crate::utils::*; +use crate::utils::{Post, Preferences, Subreddit, cookie, error, format_num, format_url, param, redirect, request, rewrite_urls, template, val}; use askama::Template; use tide::{http::Cookie, Request}; use time::{Duration, OffsetDateTime}; @@ -108,10 +108,10 @@ pub async fn subscriptions(req: Request<()>) -> tide::Result { // Redirect back to subreddit // check for redirect parameter if unsubscribing from outside sidebar let redirect_path = param(&format!("/?{}", query), "redirect"); - let path = if !redirect_path.is_empty() { - format!("/{}/", redirect_path) - } else { + let path = if redirect_path.is_empty() { format!("/r/{}", sub) + } else { + format!("/{}/", redirect_path) }; let mut res = redirect(path); @@ -139,9 +139,9 @@ pub async fn wiki(req: Request<()>) -> tide::Result { let path: String = format!("/r/{}/wiki/{}.json?raw_json=1", sub, page); match request(path).await { - Ok(res) => template(WikiTemplate { + Ok(response) => template(WikiTemplate { sub, - wiki: rewrite_urls(res["data"]["content_html"].as_str().unwrap_or_default()), + wiki: rewrite_urls(response["data"]["content_html"].as_str().unwrap_or_default()), page, prefs: Preferences::new(req), }), @@ -159,8 +159,8 @@ async fn subreddit(sub: &str) -> Result { // If success, receive JSON in response Ok(res) => { // Metadata regarding the subreddit - let members: i64 = res["data"]["subscribers"].as_u64().unwrap_or_default() as i64; - let active: i64 = res["data"]["accounts_active"].as_u64().unwrap_or_default() as i64; + let members: i64 = res["data"]["subscribers"].as_i64().unwrap_or_default(); + let active: i64 = res["data"]["accounts_active"].as_i64().unwrap_or_default(); // 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]); diff --git a/src/user.rs b/src/user.rs index 7dfd5a1..79c758a 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,5 +1,5 @@ // CRATES -use crate::utils::*; +use crate::utils::{Post, Preferences, User, error, format_url, param, request, template}; use askama::Template; use tide::Request; use time::OffsetDateTime; @@ -55,7 +55,7 @@ async fn user(name: &str) -> Result { // If success, receive JSON in response Ok(res) => { // Grab creation date as unix timestamp - let created: i64 = res["data"]["created"].as_f64().unwrap_or(0.0).round() as i64; + let created: i64 = res["data"]["created"].as_i64().unwrap_or(0); // nested_val function used to parse JSON from Reddit APIs let about = |item| res["data"]["subreddit"][item].as_str().unwrap_or_default().to_string(); diff --git a/src/utils.rs b/src/utils.rs index 2a60417..dae78ec 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -123,7 +123,7 @@ impl Media { let url = if post_type == "self" || post_type == "link" { url_val.as_str().unwrap_or_default().to_string() } else { - format_url(url_val.as_str().unwrap_or_default()).to_string() + format_url(url_val.as_str().unwrap_or_default()) }; ( @@ -221,7 +221,7 @@ impl Post { for post in post_list { let data = &post["data"]; - let (rel_time, created) = time(data["created_utc"].as_f64().unwrap_or_default()); + let (rel_time, created) = time(data["created_utc"].as_i64().unwrap_or_default()); let score = data["score"].as_i64().unwrap_or_default(); let ratio: f64 = data["upvote_ratio"].as_f64().unwrap_or(1.0) * 100.0; let title = val(post, "title"); @@ -249,7 +249,7 @@ impl Post { distinguished: val(post, "distinguished"), }, score: if data["hide_score"].as_bool().unwrap_or_default() { - "•".to_string() + "\u{2022}".to_string() } else { format_num(score) }, @@ -459,8 +459,8 @@ pub fn format_num(num: i64) -> String { } // Parse a relative and absolute time from a UNIX timestamp -pub fn time(created: f64) -> (String, String) { - let time = OffsetDateTime::from_unix_timestamp(created.round() as i64); +pub fn time(created: i64) -> (String, String) { + let time = OffsetDateTime::from_unix_timestamp(created); let time_delta = OffsetDateTime::now_utc() - time; // If the time difference is more than a month, show full date