Settings with Layouts
This commit is contained in:
@ -5,7 +5,7 @@ use actix_web::{get, middleware::NormalizePath, web, App, HttpResponse, HttpServ
|
||||
mod post;
|
||||
mod proxy;
|
||||
mod search;
|
||||
// mod settings;
|
||||
mod settings;
|
||||
mod subreddit;
|
||||
mod user;
|
||||
mod utils;
|
||||
@ -52,8 +52,8 @@ async fn main() -> std::io::Result<()> {
|
||||
.route("/favicon.ico/", web::get().to(HttpResponse::Ok))
|
||||
.route("/robots.txt/", web::get().to(robots))
|
||||
// SETTINGS SERVICE
|
||||
// .route("/settings/", web::get().to(settings::get))
|
||||
// .route("/settings/save/", web::post().to(settings::set))
|
||||
.route("/settings/", web::get().to(settings::get))
|
||||
.route("/settings/", web::post().to(settings::set))
|
||||
// PROXY SERVICE
|
||||
.route("/proxy/{url:.*}/", web::get().to(proxy::handler))
|
||||
// SEARCH SERVICES
|
||||
|
33
src/post.rs
33
src/post.rs
@ -1,5 +1,5 @@
|
||||
// CRATES
|
||||
use crate::utils::{error, format_num, format_url, param, request, rewrite_url, val, Comment, Flags, Flair, Post};
|
||||
use crate::utils::{Comment, Flags, Flair, Post, cookie, error, format_num, format_url, media, param, request, rewrite_url, val};
|
||||
use actix_web::{HttpRequest, HttpResponse, Result};
|
||||
|
||||
use async_recursion::async_recursion;
|
||||
@ -14,6 +14,7 @@ struct PostTemplate {
|
||||
comments: Vec<Comment>,
|
||||
post: Post,
|
||||
sort: String,
|
||||
layout: String,
|
||||
}
|
||||
|
||||
pub async fn item(req: HttpRequest) -> HttpResponse {
|
||||
@ -33,7 +34,14 @@ pub async fn item(req: HttpRequest) -> HttpResponse {
|
||||
let comments = parse_comments(&res[1]).await.unwrap();
|
||||
|
||||
// Use the Post and Comment structs to generate a website to show users
|
||||
let s = PostTemplate { comments, post, sort }.render().unwrap();
|
||||
let s = PostTemplate {
|
||||
comments,
|
||||
post,
|
||||
sort,
|
||||
layout: cookie(req, "layout"),
|
||||
}
|
||||
.render()
|
||||
.unwrap();
|
||||
HttpResponse::Ok().content_type("text/html").body(s)
|
||||
}
|
||||
// If the Reddit API returns an error, exit and send error page to user
|
||||
@ -41,26 +49,6 @@ pub async fn item(req: HttpRequest) -> HttpResponse {
|
||||
}
|
||||
}
|
||||
|
||||
// UTILITIES
|
||||
async fn media(data: &serde_json::Value) -> (String, String) {
|
||||
let post_type: &str;
|
||||
let url = if !data["preview"]["reddit_video_preview"]["fallback_url"].is_null() {
|
||||
post_type = "video";
|
||||
format_url(data["preview"]["reddit_video_preview"]["fallback_url"].as_str().unwrap_or_default().to_string())
|
||||
} else if !data["secure_media"]["reddit_video"]["fallback_url"].is_null() {
|
||||
post_type = "video";
|
||||
format_url(data["secure_media"]["reddit_video"]["fallback_url"].as_str().unwrap_or_default().to_string())
|
||||
} else if data["post_hint"].as_str().unwrap_or("") == "image" {
|
||||
post_type = "image";
|
||||
format_url(data["preview"]["images"][0]["source"]["url"].as_str().unwrap_or_default().to_string())
|
||||
} else {
|
||||
post_type = "link";
|
||||
data["url"].as_str().unwrap_or_default().to_string()
|
||||
};
|
||||
|
||||
(post_type.to_string(), url)
|
||||
}
|
||||
|
||||
// POSTS
|
||||
async fn parse_post(json: &serde_json::Value) -> Result<Post, &'static str> {
|
||||
// Retrieve post (as opposed to comments) from JSON
|
||||
@ -91,6 +79,7 @@ async fn parse_post(json: &serde_json::Value) -> Result<Post, &'static str> {
|
||||
score: format_num(score),
|
||||
upvote_ratio: ratio as i64,
|
||||
post_type: media.0,
|
||||
thumbnail: format_url(val(post, "thumbnail")),
|
||||
flair: Flair(
|
||||
val(post, "link_flair_text"),
|
||||
val(post, "link_flair_background_color"),
|
||||
|
@ -1,5 +1,5 @@
|
||||
// CRATES
|
||||
use crate::utils::{error, fetch_posts, param, Post};
|
||||
use crate::utils::{cookie, error, fetch_posts, param, Post};
|
||||
use actix_web::{HttpRequest, HttpResponse};
|
||||
use askama::Template;
|
||||
|
||||
@ -19,6 +19,7 @@ struct SearchTemplate {
|
||||
posts: Vec<Post>,
|
||||
sub: String,
|
||||
params: SearchParams,
|
||||
layout: String,
|
||||
}
|
||||
|
||||
// SERVICES
|
||||
@ -44,6 +45,7 @@ pub async fn find(req: HttpRequest) -> HttpResponse {
|
||||
after: posts.1,
|
||||
restrict_sr: param(&path, "restrict_sr"),
|
||||
},
|
||||
layout: cookie(req, "layout"),
|
||||
}
|
||||
.render()
|
||||
.unwrap(),
|
||||
|
@ -1,48 +1,48 @@
|
||||
// // CRATES
|
||||
// use crate::utils::cookies;
|
||||
// use actix_web::{cookie::Cookie, web::Form, HttpRequest, HttpResponse, Result}; // http::Method,
|
||||
// use askama::Template;
|
||||
// CRATES
|
||||
use crate::utils::cookie;
|
||||
use actix_web::{cookie::Cookie, web::Form, HttpRequest, HttpResponse}; // http::Method,
|
||||
use askama::Template;
|
||||
use time::{Duration, OffsetDateTime};
|
||||
|
||||
// // STRUCTS
|
||||
// #[derive(Template)]
|
||||
// #[template(path = "settings.html", escape = "none")]
|
||||
// struct SettingsTemplate {
|
||||
// pref_nsfw: String,
|
||||
// }
|
||||
// STRUCTS
|
||||
#[derive(Template)]
|
||||
#[template(path = "settings.html", escape = "none")]
|
||||
struct SettingsTemplate {
|
||||
layout: String,
|
||||
}
|
||||
|
||||
// #[derive(serde::Deserialize)]
|
||||
// pub struct Preferences {
|
||||
// pref_nsfw: Option<String>,
|
||||
// }
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct Preferences {
|
||||
layout: Option<String>,
|
||||
}
|
||||
|
||||
// // FUNCTIONS
|
||||
// FUNCTIONS
|
||||
|
||||
// // Retrieve cookies from request "Cookie" header
|
||||
// pub async fn get(req: HttpRequest) -> Result<HttpResponse> {
|
||||
// let cookies = cookies(req);
|
||||
// Retrieve cookies from request "Cookie" header
|
||||
pub async fn get(req: HttpRequest) -> HttpResponse {
|
||||
let s = SettingsTemplate { layout: cookie(req, "layout") }.render().unwrap();
|
||||
|
||||
// let pref_nsfw: String = cookies.get("pref_nsfw").unwrap_or(&String::new()).to_owned();
|
||||
HttpResponse::Ok().content_type("text/html").body(s)
|
||||
}
|
||||
|
||||
// let s = SettingsTemplate { pref_nsfw }.render().unwrap();
|
||||
// Ok(HttpResponse::Ok().content_type("text/html").body(s))
|
||||
// }
|
||||
// Set cookies using response "Set-Cookie" header
|
||||
pub async fn set(req: HttpRequest, form: Form<Preferences>) -> HttpResponse {
|
||||
let mut response = HttpResponse::Found();
|
||||
|
||||
// // Set cookies using response "Set-Cookie" header
|
||||
// pub async fn set(form: Form<Preferences>) -> HttpResponse {
|
||||
// let nsfw: Cookie = match &form.pref_nsfw {
|
||||
// Some(value) => Cookie::build("pref_nsfw", value).path("/").secure(true).http_only(true).finish(),
|
||||
// None => Cookie::build("pref_nsfw", "").finish(),
|
||||
// };
|
||||
match &form.layout {
|
||||
Some(value) => response.cookie(
|
||||
Cookie::build("layout", value)
|
||||
.path("/")
|
||||
.secure(true)
|
||||
.http_only(true)
|
||||
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
||||
.finish(),
|
||||
),
|
||||
None => response.del_cookie(&actix_web::HttpMessage::cookie(&req, "layout").unwrap()),
|
||||
};
|
||||
|
||||
// let body = SettingsTemplate {
|
||||
// pref_nsfw: form.pref_nsfw.clone().unwrap_or_default(),
|
||||
// }
|
||||
// .render()
|
||||
// .unwrap();
|
||||
|
||||
// HttpResponse::Found()
|
||||
// .content_type("text/html")
|
||||
// .set_header("Set-Cookie", nsfw.to_string())
|
||||
// .set_header("Location", "/settings")
|
||||
// .body(body)
|
||||
// }
|
||||
response
|
||||
.content_type("text/html")
|
||||
.set_header("Location", "/settings")
|
||||
.body(r#"Redirecting to <a href="/settings">settings</a>..."#)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// CRATES
|
||||
use crate::utils::{error, fetch_posts, format_num, format_url, param, request, rewrite_url, val, Post, Subreddit};
|
||||
use crate::utils::{cookie, error, fetch_posts, format_num, format_url, param, request, rewrite_url, val, Post, Subreddit};
|
||||
use actix_web::{HttpRequest, HttpResponse, Result};
|
||||
use askama::Template;
|
||||
|
||||
@ -11,6 +11,7 @@ struct SubredditTemplate {
|
||||
posts: Vec<Post>,
|
||||
sort: (String, String),
|
||||
ends: (String, String),
|
||||
layout: String,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
@ -19,6 +20,7 @@ struct WikiTemplate {
|
||||
sub: String,
|
||||
wiki: String,
|
||||
page: String,
|
||||
layout: String,
|
||||
}
|
||||
|
||||
// SERVICES
|
||||
@ -40,6 +42,7 @@ pub async fn page(req: HttpRequest) -> HttpResponse {
|
||||
posts: items.0,
|
||||
sort: (sort, param(&path, "t")),
|
||||
ends: (param(&path, "after"), items.1),
|
||||
layout: cookie(req, "layout"),
|
||||
}
|
||||
.render()
|
||||
.unwrap();
|
||||
@ -60,6 +63,7 @@ pub async fn wiki(req: HttpRequest) -> HttpResponse {
|
||||
sub: sub.to_string(),
|
||||
wiki: rewrite_url(res["data"]["content_html"].as_str().unwrap_or_default()),
|
||||
page: page.to_string(),
|
||||
layout: String::new(),
|
||||
}
|
||||
.render()
|
||||
.unwrap();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// CRATES
|
||||
use crate::utils::{error, fetch_posts, format_url, nested_val, param, request, Post, User};
|
||||
use crate::utils::{cookie, error, fetch_posts, format_url, nested_val, param, request, Post, User};
|
||||
use actix_web::{HttpRequest, HttpResponse, Result};
|
||||
use askama::Template;
|
||||
use chrono::{TimeZone, Utc};
|
||||
@ -12,6 +12,7 @@ struct UserTemplate {
|
||||
posts: Vec<Post>,
|
||||
sort: (String, String),
|
||||
ends: (String, String),
|
||||
layout: String,
|
||||
}
|
||||
|
||||
// FUNCTIONS
|
||||
@ -34,6 +35,7 @@ pub async fn profile(req: HttpRequest) -> HttpResponse {
|
||||
posts: items.0,
|
||||
sort: (sort, param(&path, "t")),
|
||||
ends: (param(&path, "after"), items.1),
|
||||
layout: cookie(req, "layout"),
|
||||
}
|
||||
.render()
|
||||
.unwrap();
|
||||
|
66
src/utils.rs
66
src/utils.rs
@ -1,9 +1,11 @@
|
||||
// use std::collections::HashMap;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
//
|
||||
// CRATES
|
||||
//
|
||||
use actix_web::{HttpResponse, Result};
|
||||
use actix_web::{cookie::Cookie, HttpResponse, Result};
|
||||
use askama::Template;
|
||||
use base64::encode;
|
||||
use chrono::{TimeZone, Utc};
|
||||
@ -37,6 +39,7 @@ pub struct Post {
|
||||
pub post_type: String,
|
||||
pub flair: Flair,
|
||||
pub flags: Flags,
|
||||
pub thumbnail: String,
|
||||
pub media: String,
|
||||
pub time: String,
|
||||
}
|
||||
@ -91,6 +94,7 @@ pub struct Params {
|
||||
#[template(path = "error.html", escape = "none")]
|
||||
pub struct ErrorTemplate {
|
||||
pub message: String,
|
||||
pub layout: String,
|
||||
}
|
||||
|
||||
//
|
||||
@ -100,27 +104,14 @@ pub struct ErrorTemplate {
|
||||
// Grab a query param from a url
|
||||
pub fn param(path: &str, value: &str) -> String {
|
||||
let url = Url::parse(format!("https://libredd.it/{}", path).as_str()).unwrap();
|
||||
let pairs: std::collections::HashMap<_, _> = url.query_pairs().into_owned().collect();
|
||||
let pairs: HashMap<_, _> = url.query_pairs().into_owned().collect();
|
||||
pairs.get(value).unwrap_or(&String::new()).to_owned()
|
||||
}
|
||||
|
||||
// Cookies from request
|
||||
// pub fn cookies(req: HttpRequest) -> HashMap<String, String> {
|
||||
// let mut result: HashMap<String, String> = HashMap::new();
|
||||
|
||||
// let cookies: Vec<Cookie> = req
|
||||
// .headers()
|
||||
// .get_all("Cookie")
|
||||
// .map(|value| value.to_str().unwrap())
|
||||
// .map(|unparsed| Cookie::parse(unparsed).unwrap())
|
||||
// .collect();
|
||||
|
||||
// for cookie in cookies {
|
||||
// result.insert(cookie.name().to_string(), cookie.value().to_string());
|
||||
// }
|
||||
|
||||
// result
|
||||
// }
|
||||
// Cookie value from request
|
||||
pub fn cookie(req: actix_web::HttpRequest, name: &str) -> String {
|
||||
actix_web::HttpMessage::cookie(&req, name).unwrap_or_else(|| Cookie::new(name, "")).value().to_string()
|
||||
}
|
||||
|
||||
// Direct urls to proxy if proxy is enabled
|
||||
pub fn format_url(url: String) -> String {
|
||||
@ -148,6 +139,25 @@ pub fn format_num(num: i64) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn media(data: &serde_json::Value) -> (String, String) {
|
||||
let post_type: &str;
|
||||
let url = if !data["preview"]["reddit_video_preview"]["fallback_url"].is_null() {
|
||||
post_type = "video";
|
||||
format_url(data["preview"]["reddit_video_preview"]["fallback_url"].as_str().unwrap_or_default().to_string())
|
||||
} else if !data["secure_media"]["reddit_video"]["fallback_url"].is_null() {
|
||||
post_type = "video";
|
||||
format_url(data["secure_media"]["reddit_video"]["fallback_url"].as_str().unwrap_or_default().to_string())
|
||||
} else if data["post_hint"].as_str().unwrap_or("") == "image" {
|
||||
post_type = "image";
|
||||
format_url(data["preview"]["images"][0]["source"]["url"].as_str().unwrap_or_default().to_string())
|
||||
} else {
|
||||
post_type = "link";
|
||||
data["url"].as_str().unwrap_or_default().to_string()
|
||||
};
|
||||
|
||||
(post_type.to_string(), url)
|
||||
}
|
||||
|
||||
//
|
||||
// JSON PARSING
|
||||
//
|
||||
@ -187,12 +197,16 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
|
||||
|
||||
// For each post from posts list
|
||||
for post in post_list {
|
||||
let img = format_url(val(post, "thumbnail"));
|
||||
let unix_time: i64 = post["data"]["created_utc"].as_f64().unwrap_or_default().round() as i64;
|
||||
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;
|
||||
let title = val(post, "title");
|
||||
|
||||
// Determine the type of media along with the media URL
|
||||
let media = media(&post["data"]).await;
|
||||
|
||||
dbg!(post["data"]["id"].to_string());
|
||||
|
||||
posts.push(Post {
|
||||
id: val(post, "id"),
|
||||
title: if title.is_empty() { fallback_title.to_owned() } else { title },
|
||||
@ -206,8 +220,9 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
|
||||
),
|
||||
score: format_num(score),
|
||||
upvote_ratio: ratio as i64,
|
||||
post_type: "link".to_string(),
|
||||
media: img,
|
||||
post_type: media.0,
|
||||
thumbnail: format_url(val(post, "thumbnail")),
|
||||
media: media.1,
|
||||
flair: Flair(
|
||||
val(post, "link_flair_text"),
|
||||
val(post, "link_flair_background_color"),
|
||||
@ -234,7 +249,12 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
|
||||
//
|
||||
|
||||
pub async fn error(msg: String) -> HttpResponse {
|
||||
let body = ErrorTemplate { message: msg }.render().unwrap_or_default();
|
||||
let body = ErrorTemplate {
|
||||
message: msg,
|
||||
layout: String::new(),
|
||||
}
|
||||
.render()
|
||||
.unwrap_or_default();
|
||||
HttpResponse::NotFound().content_type("text/html").body(body)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user