diff --git a/src/main.rs b/src/main.rs index f45ed70..6a3553b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,11 +58,12 @@ async fn main() -> std::io::Result<()> { // USER SERVICES .route("/u/{username}/", web::get().to(user::profile)) .route("/user/{username}/", web::get().to(user::profile)) + // WIKI SERVICES + .route("/r/{sub}/wiki/", web::get().to(subreddit::wiki)) + .route("/r/{sub}/wiki/{page}/", web::get().to(subreddit::wiki)) // SUBREDDIT SERVICES .route("/r/{sub}/", web::get().to(subreddit::page)) - .route("/r/{sub}/{sort}/", web::get().to(subreddit::page)) - // WIKI SERVICES - // .route("/r/{sub}/wiki/index", web::get().to(subreddit::wiki)) + .route("/r/{sub}/{sort:hot|new|top|rising}/", web::get().to(subreddit::page)) // POPULAR SERVICES .route("/", web::get().to(subreddit::page)) .route("/{sort:best|hot|new|top|rising}/", web::get().to(subreddit::page)) diff --git a/src/post.rs b/src/post.rs index 6d8423e..c33359e 100644 --- a/src/post.rs +++ b/src/post.rs @@ -24,7 +24,7 @@ pub async fn item(req: HttpRequest) -> Result { // Log the post ID being fetched in debug mode #[cfg(debug_assertions)] dbg!(&id); - + // Send a request to the url, receive JSON in response match request(&path).await { // Otherwise, grab the JSON output from the request @@ -36,9 +36,9 @@ pub async fn item(req: HttpRequest) -> Result { // Use the Post and Comment structs to generate a website to show users let s = PostTemplate { comments, post, sort }.render().unwrap(); Ok(HttpResponse::Ok().content_type("text/html").body(s)) - }, + } // If the Reddit API returns an error, exit and send error page to user - Err(msg) => error(msg.to_string()).await + Err(msg) => error(msg.to_string()).await, } } diff --git a/src/search.rs b/src/search.rs index 2e26af9..34d8d0a 100644 --- a/src/search.rs +++ b/src/search.rs @@ -38,7 +38,7 @@ pub async fn find(req: HttpRequest) -> Result { .render() .unwrap(); Ok(HttpResponse::Ok().content_type("text/html").body(s)) - }, - Err(msg) => error(msg.to_string()).await + } + Err(msg) => error(msg.to_string()).await, } } diff --git a/src/subreddit.rs b/src/subreddit.rs index a13ac47..9f0bdca 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -13,8 +13,14 @@ struct SubredditTemplate { ends: (String, String), } +#[derive(Template)] +#[template(path = "wiki.html", escape = "none")] +struct WikiTemplate { + sub: String, + wiki: String, +} + // SERVICES -// web::Path(sub): web::Path, params: web::Query pub async fn page(req: HttpRequest) -> Result { let path = format!("{}.json?{}", req.path(), req.query_string()); let sub = req.match_info().get("sub").unwrap_or("popular").to_string(); @@ -37,8 +43,27 @@ pub async fn page(req: HttpRequest) -> Result { .render() .unwrap(); Ok(HttpResponse::Ok().content_type("text/html").body(s)) - }, - Err(msg) => error(msg.to_string()).await + } + Err(msg) => error(msg.to_string()).await, + } +} + +pub async fn wiki(req: HttpRequest) -> Result { + let sub = req.match_info().get("sub").unwrap(); + let page = req.match_info().get("page").unwrap_or("index"); + let path: String = format!("r/{}/wiki/{}.json?raw_json=1", sub, page); + + match request(&path).await { + Ok(res) => { + let s = WikiTemplate { + sub: sub.to_string(), + wiki: res["data"]["content_html"].as_str().unwrap().to_string(), + } + .render() + .unwrap(); + Ok(HttpResponse::Ok().content_type("text/html").body(s)) + } + Err(msg) => error(msg.to_string()).await, } } @@ -47,33 +72,32 @@ async fn subreddit(sub: &str) -> Result { // Build the Reddit JSON API url let path: String = format!("r/{}/about.json?raw_json=1", sub); - let res; - // Send a request to the url match request(&path).await { // If success, receive JSON in response - Ok(response) => { res = 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; + + // Fetch subreddit icon either from the community_icon or icon_img value + let community_icon: &str = res["data"]["community_icon"].as_str().unwrap_or("").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"), + title: val(&res, "title"), + description: val(&res, "public_description"), + info: val(&res, "description_html").replace("\\", ""), + icon: format_url(icon).await, + members: format_num(members), + active: format_num(active), + wiki: res["data"]["wiki_enabled"].as_bool().unwrap_or_default(), + }; + + Ok(sub) + } // If the Reddit API returns an error, exit this function - Err(msg) => return Err(msg) + Err(msg) => return Err(msg), } - - // 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; - - // Fetch subreddit icon either from the community_icon or icon_img value - let community_icon: &str = res["data"]["community_icon"].as_str().unwrap_or("").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"), - title: val(&res, "title"), - description: val(&res, "public_description"), - info: val(&res, "description_html").replace("\\", ""), - icon: format_url(icon).await, - members: format_num(members), - active: format_num(active), - }; - - Ok(sub) } diff --git a/src/user.rs b/src/user.rs index 3410be4..d3e0386 100644 --- a/src/user.rs +++ b/src/user.rs @@ -25,7 +25,7 @@ pub async fn profile(req: HttpRequest) -> Result { // Request user profile data and user posts/comments from Reddit let user = user(&username).await; let posts = fetch_posts(&path, "Comment".to_string()).await; - + match posts { Ok(items) => { let s = UserTemplate { @@ -37,9 +37,9 @@ pub async fn profile(req: HttpRequest) -> Result { .render() .unwrap(); Ok(HttpResponse::Ok().content_type("text/html").body(s)) - }, + } // If there is an error show error page - Err(msg) => error(msg.to_string()).await + Err(msg) => error(msg.to_string()).await, } } @@ -53,9 +53,11 @@ async fn user(name: &str) -> Result { // Send a request to the url match request(&path).await { // If success, receive JSON in response - Ok(response) => { res = response; }, + Ok(response) => { + res = response; + } // If the Reddit API returns an error, exit this function - Err(msg) => return Err(msg) + Err(msg) => return Err(msg), } // Grab creation date as unix timestamp diff --git a/src/utils.rs b/src/utils.rs index 494b764..0d6b18c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,7 +4,7 @@ use actix_web::{http::StatusCode, HttpResponse, Result}; use askama::Template; use chrono::{TimeZone, Utc}; -use serde_json::{from_str}; +use serde_json::from_str; use url::Url; // use surf::{client, get, middleware::Redirect}; @@ -70,6 +70,7 @@ pub struct Subreddit { pub icon: String, pub members: String, pub active: String, + pub wiki: bool, } // Parser for query params, used in sorting (eg. /r/rust/?sort=hot) @@ -130,7 +131,7 @@ pub fn format_num(num: i64) -> String { // val() function used to parse JSON from Reddit APIs pub fn val(j: &serde_json::Value, k: &str) -> String { - String::from(j["data"][k].as_str().unwrap_or("")) + String::from(j["data"][k].as_str().unwrap_or_default()) } // nested_val() function used to parse JSON from Reddit APIs @@ -146,15 +147,17 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec { res = response; }, + Ok(response) => { + res = response; + } // If the Reddit API returns an error, exit this function - Err(msg) => return Err(msg) + Err(msg) => return Err(msg), } // Fetch the list of posts from the JSON response match res["data"]["children"].as_array() { - Some(list) => { post_list = list }, - None => { return Err("No posts found") } + Some(list) => post_list = list, + None => return Err("No posts found"), } let mut posts: Vec = Vec::new(); @@ -250,7 +253,7 @@ pub async fn request(path: &str) -> Result { Err("Failed to parse page JSON data") } } - }, + } false => { #[cfg(debug_assertions)] dbg!(format!("{} - Page not found", url)); diff --git a/static/style.css b/static/style.css index 3c69669..7782761 100644 --- a/static/style.css +++ b/static/style.css @@ -24,7 +24,6 @@ body { background: var(--background); - visibility: visible !important; } nav { @@ -49,7 +48,11 @@ main { margin: 20px auto; } -#column_one { max-width: 750px; } +#column_one { + max-width: 750px; + border-radius: 5px; + overflow: hidden; +} footer { display: flex; @@ -100,10 +103,14 @@ aside { height: max-content; background: var(--outside); border-radius: 5px; + overflow: hidden; } #user *, #subreddit * { text-align: center; } +#subreddit { padding: 0; } +#sub_meta { padding: 20px; } + #sidebar, #sidebar_contents { margin-top: 20px; } #sidebar_label { @@ -111,7 +118,7 @@ aside { padding: 10px; } -#user_icon, #subreddit_icon { +#user_icon, #sub_icon { width: 100px; height: 100px; border: 2px solid var(--accent); @@ -120,30 +127,55 @@ aside { margin: 10px; } -#user_title, #subreddit_title { +#user_title, #sub_title { margin: 0 20px; font-size: 20px; font-weight: bold; } -#user_description, #subreddit_description { +#user_description, #sub_description { margin: 0 20px; font-size: 15px; } -#user_name, #subreddit_name, #user_icon, #subreddit_icon, #user_description, #subreddit_description { margin-bottom: 20px; } +#user_name, #sub_name, #user_icon, #sub_icon, #user_description, #sub_description { margin-bottom: 20px; } -#user_details, #subreddit_details { +#user_details, #sub_details { display: grid; grid-template-columns: repeat(2, 1fr); grid-column-gap: 20px; } -#user_details > label, #subreddit_details > label { +#user_details > label, #sub_details > label { color: var(--accent); font-size: 15px; } +/* Wiki Pages */ + +#wiki { + background: var(--foreground); + padding: 35px; +} + +#top { + background: var(--highlighted); + font-size: 18px; + width: 100%; + display: flex; +} + +#top > * { + flex-grow: 1; + text-align: center; + height: 40px; + line-height: 40px; +} + +#top > div { + border-bottom: 2px solid white; +} + /* Sorting and Search */ select { @@ -500,11 +532,11 @@ input[type="submit"]:hover { color: var(--accent); } } .md a { - text-decoration: underline; color: var(--accent); } .md li { margin: 10px 0; } +.toc_child { list-style: none; } .md pre { background: var(--outside); diff --git a/templates/base.html b/templates/base.html index 88f4e5f..ae37b97 100644 --- a/templates/base.html +++ b/templates/base.html @@ -12,7 +12,7 @@ {% endblock %} - +