Default Comment Sort Setting

This commit is contained in:
spikecodes 2021-01-07 08:38:05 -08:00
parent 7e96bb3d80
commit 3444989f9a
13 changed files with 77 additions and 42 deletions

View File

@ -12,7 +12,7 @@ base64 = "0.13.0"
actix-web = { version = "3.3.2", features = ["rustls"] } actix-web = { version = "3.3.2", features = ["rustls"] }
reqwest = { version = "0.10", default_features = false, features = ["rustls-tls"] } reqwest = { version = "0.10", default_features = false, features = ["rustls-tls"] }
askama = "0.10.5" askama = "0.10.5"
serde = "1.0.118" serde = { version = "1.0.118", default_features = false, features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
async-recursion = "0.3.1" async-recursion = "0.3.1"
url = "2.2.0" url = "2.2.0"

View File

@ -80,9 +80,6 @@ async fn main() -> std::io::Result<()> {
.route("/r/{sub}/comments/{id}/{title}/{comment_id}/", web::get().to(post::item)) .route("/r/{sub}/comments/{id}/{title}/{comment_id}/", web::get().to(post::item))
}) })
.bind(&address) .bind(&address)
.map(|x| {
x
})
.unwrap_or_else(|_| panic!("Cannot bind to the address: {}", address)) .unwrap_or_else(|_| panic!("Cannot bind to the address: {}", address))
.run() .run()
.await .await

View File

@ -14,12 +14,18 @@ struct PostTemplate {
comments: Vec<Comment>, comments: Vec<Comment>,
post: Post, post: Post,
sort: String, sort: String,
layout: String,
} }
pub async fn item(req: HttpRequest) -> HttpResponse { pub async fn item(req: HttpRequest) -> HttpResponse {
// Build Reddit API path
let path = format!("{}.json?{}&raw_json=1", req.path(), req.query_string()); let path = format!("{}.json?{}&raw_json=1", req.path(), req.query_string());
let sort = param(&path, "sort");
// Set sort to sort query parameter or otherwise default sort
let sort = if param(&path, "sort").is_empty() {
cookie(req.to_owned(), "comment_sort")
} else {
param(&path, "sort")
};
// Log the post ID being fetched in debug mode // Log the post ID being fetched in debug mode
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -34,14 +40,7 @@ pub async fn item(req: HttpRequest) -> HttpResponse {
let comments = parse_comments(&res[1]).await; let comments = parse_comments(&res[1]).await;
// Use the Post and Comment structs to generate a website to show users // Use the Post and Comment structs to generate a website to show users
let s = PostTemplate { let s = PostTemplate { comments, post, sort }.render().unwrap();
comments,
post,
sort,
layout: cookie(req, "layout"),
}
.render()
.unwrap();
HttpResponse::Ok().content_type("text/html").body(s) HttpResponse::Ok().content_type("text/html").body(s)
} }
// If the Reddit API returns an error, exit and send error page to user // If the Reddit API returns an error, exit and send error page to user

View File

@ -6,27 +6,33 @@ use time::{Duration, OffsetDateTime};
// STRUCTS // STRUCTS
#[derive(Template)] #[derive(Template)]
#[template(path = "settings.html", escape = "none")] #[template(path = "settings.html")]
struct SettingsTemplate { struct SettingsTemplate {
layout: String, layout: String,
comment_sort: String,
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct Preferences { pub struct SettingsForm {
layout: Option<String>, layout: Option<String>,
comment_sort: Option<String>,
} }
// FUNCTIONS // FUNCTIONS
// Retrieve cookies from request "Cookie" header // Retrieve cookies from request "Cookie" header
pub async fn get(req: HttpRequest) -> HttpResponse { pub async fn get(req: HttpRequest) -> HttpResponse {
let s = SettingsTemplate { layout: cookie(req, "layout") }.render().unwrap(); let s = SettingsTemplate {
layout: cookie(req.to_owned(), "layout"),
comment_sort: cookie(req, "comment_sort"),
}
.render()
.unwrap();
HttpResponse::Ok().content_type("text/html").body(s) HttpResponse::Ok().content_type("text/html").body(s)
} }
// Set cookies using response "Set-Cookie" header // Set cookies using response "Set-Cookie" header
pub async fn set(req: HttpRequest, form: Form<Preferences>) -> HttpResponse { pub async fn set(req: HttpRequest, form: Form<SettingsForm>) -> HttpResponse {
let mut response = HttpResponse::Found(); let mut response = HttpResponse::Found();
match &form.layout { match &form.layout {
@ -40,6 +46,17 @@ pub async fn set(req: HttpRequest, form: Form<Preferences>) -> HttpResponse {
None => response.del_cookie(&actix_web::HttpMessage::cookie(&req, "layout").unwrap()), None => response.del_cookie(&actix_web::HttpMessage::cookie(&req, "layout").unwrap()),
}; };
match &form.comment_sort {
Some(value) => response.cookie(
Cookie::build("comment_sort", value)
.path("/")
.http_only(true)
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
.finish(),
),
None => response.del_cookie(&actix_web::HttpMessage::cookie(&req, "comment_sort").unwrap()),
};
response response
.content_type("text/html") .content_type("text/html")
.set_header("Location", "/settings") .set_header("Location", "/settings")

View File

@ -20,17 +20,16 @@ struct WikiTemplate {
sub: String, sub: String,
wiki: String, wiki: String,
page: String, page: String,
layout: String,
} }
// SERVICES // SERVICES
pub async fn page(req: HttpRequest) -> HttpResponse { pub async fn page(req: HttpRequest) -> HttpResponse {
let path = format!("{}.json?{}", req.path(), req.query_string()); let path = format!("{}.json?{}", req.path(), req.query_string());
let sub = req.match_info().get("sub").unwrap_or("popular").to_string(); let sub_name = req.match_info().get("sub").unwrap_or("popular").to_string();
let sort = req.match_info().get("sort").unwrap_or("hot").to_string(); let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
let sub_result = if !&sub.contains('+') && sub != "popular" { let sub = if !&sub_name.contains('+') && sub_name != "popular" {
subreddit(&sub).await.unwrap_or_default() subreddit(&sub_name).await.unwrap_or_default()
} else { } else {
Subreddit::default() Subreddit::default()
}; };
@ -38,8 +37,8 @@ pub async fn page(req: HttpRequest) -> HttpResponse {
match fetch_posts(&path, String::new()).await { match fetch_posts(&path, String::new()).await {
Ok((posts, after)) => { Ok((posts, after)) => {
let s = SubredditTemplate { let s = SubredditTemplate {
sub: sub_result, sub,
posts: posts, posts,
sort: (sort, param(&path, "t")), sort: (sort, param(&path, "t")),
ends: (param(&path, "after"), after), ends: (param(&path, "after"), after),
layout: cookie(req, "layout"), layout: cookie(req, "layout"),
@ -63,7 +62,6 @@ pub async fn wiki(req: HttpRequest) -> HttpResponse {
sub: sub.to_string(), sub: sub.to_string(),
wiki: rewrite_url(res["data"]["content_html"].as_str().unwrap_or_default()), wiki: rewrite_url(res["data"]["content_html"].as_str().unwrap_or_default()),
page: page.to_string(), page: page.to_string(),
layout: String::new(),
} }
.render() .render()
.unwrap(); .unwrap();

View File

@ -94,7 +94,6 @@ pub struct Params {
#[template(path = "error.html", escape = "none")] #[template(path = "error.html", escape = "none")]
pub struct ErrorTemplate { pub struct ErrorTemplate {
pub message: String, pub message: String,
pub layout: String,
} }
// //
@ -180,7 +179,9 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
// Send a request to the url // Send a request to the url
match request(&path).await { match request(&path).await {
// If success, receive JSON in response // If success, receive JSON in response
Ok(response) => { res = response; } Ok(response) => {
res = response;
}
// If the Reddit API returns an error, exit this function // If the Reddit API returns an error, exit this function
Err(msg) => return Err(msg), Err(msg) => return Err(msg),
} }
@ -245,12 +246,7 @@ pub async fn fetch_posts(path: &str, fallback_title: String) -> Result<(Vec<Post
// //
pub async fn error(msg: String) -> HttpResponse { pub async fn error(msg: String) -> HttpResponse {
let body = ErrorTemplate { let body = ErrorTemplate { message: msg }.render().unwrap_or_default();
message: msg,
layout: String::new(),
}
.render()
.unwrap_or_default();
HttpResponse::NotFound().content_type("text/html").body(body) HttpResponse::NotFound().content_type("text/html").body(body)
} }

View File

@ -622,6 +622,7 @@ input[type="submit"]:hover { color: var(--accent); }
#prefs { #prefs {
display: flex; display: flex;
flex-direction: column;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 20px; padding: 20px;
@ -629,8 +630,20 @@ input[type="submit"]:hover { color: var(--accent); }
border-radius: 5px; border-radius: 5px;
} }
#prefs > select { #prefs > div {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
#prefs > div:not(:last-of-type) {
margin-bottom: 10px;
}
#prefs select {
border-radius: 5px; border-radius: 5px;
box-shadow: var(--shadow);
margin-left: 20px; margin-left: 20px;
} }

View File

@ -11,7 +11,7 @@
<link rel="stylesheet" href="/style.css"> <link rel="stylesheet" href="/style.css">
{% endblock %} {% endblock %}
</head> </head>
<body {% if layout != "" %}id="{{ layout }}"{% endif %}> <body id="{% block layout %}{% endblock %}">
<!-- NAVIGATION BAR --> <!-- NAVIGATION BAR -->
<nav> <nav>
<p id="logo"> <p id="logo">

View File

@ -88,7 +88,7 @@
<!-- SORT FORM --> <!-- SORT FORM -->
<form id="sort"> <form id="sort">
<select name="sort"> <select name="sort">
{% call utils::options(sort, ["confidence", "top", "new", "controversial", "old"], "") %} {% call utils::options(sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
</select><input id="sort_submit" type="submit" value="&rarr;"> </select><input id="sort_submit" type="submit" value="&rarr;">
</form> </form>

View File

@ -3,6 +3,8 @@
{% block title %}Libreddit: search results - {{ params.q }}{% endblock %} {% block title %}Libreddit: search results - {{ params.q }}{% endblock %}
{% block layout %}{% if layout != "" %}{{ layout }}{% endif %}{% endblock %}
{% block content %} {% block content %}
<div id="column_one"> <div id="column_one">
<form id="search_sort"> <form id="search_sort">

View File

@ -11,11 +11,19 @@
<main> <main>
<form id="settings" action="/settings" method="POST"> <form id="settings" action="/settings" method="POST">
<div id="prefs"> <div id="prefs">
<div id="layout">
<label for="layout">Layout:</label> <label for="layout">Layout:</label>
<select name="layout"> <select name="layout">
{% call utils::options(layout, ["card", "clean", "compact"], "clean") %} {% call utils::options(layout, ["card", "clean", "compact"], "clean") %}
</select> </select>
</div> </div>
<div id="comment_sort">
<label for="comment_sort">Default comment sort:</label>
<select name="comment_sort">
{% call utils::options(comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
</select>
</div>
</div>
<input id="save" type="submit" value="Save"> <input id="save" type="submit" value="Save">
</form> </form>
</main> </main>

View File

@ -11,6 +11,8 @@
{% call utils::search(["/r/", sub.name.as_str()].concat(), "") %} {% call utils::search(["/r/", sub.name.as_str()].concat(), "") %}
{% endblock %} {% endblock %}
{% block layout %}{% if layout != "" %}{{ layout }}{% endif %}{% endblock %}
{% block body %} {% block body %}
<main> <main>
<div id="column_one"> <div id="column_one">

View File

@ -6,6 +6,9 @@
{% endblock %} {% endblock %}
{% block title %}{{ user.name.replace("u/", "") }} (u/{{ user.name }}) - Libreddit{% endblock %} {% block title %}{{ user.name.replace("u/", "") }} (u/{{ user.name }}) - Libreddit{% endblock %}
{% block layout %}{% if layout != "" %}{{ layout }}{% endif %}{% endblock %}
{% block body %} {% block body %}
<main style="max-width: 1000px;"> <main style="max-width: 1000px;">
<div id="column_one"> <div id="column_one">