Add "hide nsfw" option

This commit is contained in:
spikecodes 2021-01-08 17:35:04 -08:00
parent 3d142afd03
commit b13874d0db
10 changed files with 98 additions and 75 deletions

8
Cargo.lock generated
View File

@ -1026,9 +1026,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.81" version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
[[package]] [[package]]
name = "libreddit" name = "libreddit"
@ -1756,9 +1756,9 @@ dependencies = [
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]

View File

@ -1,5 +1,5 @@
// CRATES // CRATES
use crate::utils::{cookie, error, fetch_posts, param, Post}; use crate::utils::{error, fetch_posts, param, prefs, Post, Preferences};
use actix_web::{HttpRequest, HttpResponse}; use actix_web::{HttpRequest, HttpResponse};
use askama::Template; use askama::Template;
@ -19,7 +19,7 @@ struct SearchTemplate {
posts: Vec<Post>, posts: Vec<Post>,
sub: String, sub: String,
params: SearchParams, params: SearchParams,
layout: String, prefs: Preferences,
} }
// SERVICES // SERVICES
@ -45,7 +45,7 @@ pub async fn find(req: HttpRequest) -> HttpResponse {
after, after,
restrict_sr: param(&path, "restrict_sr"), restrict_sr: param(&path, "restrict_sr"),
}, },
layout: cookie(req, "layout"), prefs: prefs(req),
} }
.render() .render()
.unwrap(), .unwrap(),

View File

@ -1,6 +1,6 @@
// CRATES // CRATES
use crate::utils::cookie; use crate::utils::cookie;
use actix_web::{cookie::Cookie, web::Form, HttpRequest, HttpResponse}; // http::Method, use actix_web::{cookie::Cookie, web::Form, HttpMessage, HttpRequest, HttpResponse};
use askama::Template; use askama::Template;
use time::{Duration, OffsetDateTime}; use time::{Duration, OffsetDateTime};
@ -10,12 +10,14 @@ use time::{Duration, OffsetDateTime};
struct SettingsTemplate { struct SettingsTemplate {
layout: String, layout: String,
comment_sort: String, comment_sort: String,
hide_nsfw: String,
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct SettingsForm { pub struct SettingsForm {
layout: Option<String>, layout: Option<String>,
comment_sort: Option<String>, comment_sort: Option<String>,
hide_nsfw: Option<String>,
} }
// FUNCTIONS // FUNCTIONS
@ -24,7 +26,8 @@ pub struct SettingsForm {
pub async fn get(req: HttpRequest) -> HttpResponse { pub async fn get(req: HttpRequest) -> HttpResponse {
let s = SettingsTemplate { let s = SettingsTemplate {
layout: cookie(req.to_owned(), "layout"), layout: cookie(req.to_owned(), "layout"),
comment_sort: cookie(req, "comment_sort"), comment_sort: cookie(req.to_owned(), "comment_sort"),
hide_nsfw: cookie(req, "hide_nsfw"),
} }
.render() .render()
.unwrap(); .unwrap();
@ -33,31 +36,28 @@ pub async fn get(req: HttpRequest) -> HttpResponse {
// Set cookies using response "Set-Cookie" header // Set cookies using response "Set-Cookie" header
pub async fn set(req: HttpRequest, form: Form<SettingsForm>) -> HttpResponse { pub async fn set(req: HttpRequest, form: Form<SettingsForm>) -> HttpResponse {
let mut response = HttpResponse::Found(); let mut res = HttpResponse::Found();
match &form.layout { let names = vec!["layout", "comment_sort", "hide_nsfw"];
Some(value) => response.cookie( let values = vec![&form.layout, &form.comment_sort, &form.hide_nsfw];
Cookie::build("layout", value)
.path("/")
.http_only(true)
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
.finish(),
),
None => response.del_cookie(&actix_web::HttpMessage::cookie(&req, "layout").unwrap()),
};
match &form.comment_sort { for (i, name) in names.iter().enumerate() {
Some(value) => response.cookie( match values[i] {
Cookie::build("comment_sort", value) Some(value) => res.cookie(
.path("/") Cookie::build(name.to_owned(), value)
.http_only(true) .path("/")
.expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .http_only(true)
.finish(), .expires(OffsetDateTime::now_utc() + Duration::weeks(52))
), .finish(),
None => response.del_cookie(&actix_web::HttpMessage::cookie(&req, "comment_sort").unwrap()), ),
}; None => match HttpMessage::cookie(&req, name.to_owned()) {
Some(cookie) => res.del_cookie(&cookie),
None => &mut res,
},
};
}
response res
.content_type("text/html") .content_type("text/html")
.set_header("Location", "/settings") .set_header("Location", "/settings")
.body(r#"Redirecting to <a href="/settings">settings</a>..."#) .body(r#"Redirecting to <a href="/settings">settings</a>..."#)

View File

@ -1,5 +1,5 @@
// CRATES // CRATES
use crate::utils::{cookie, error, fetch_posts, format_num, format_url, param, request, rewrite_url, val, Post, Subreddit}; use crate::utils::{error, fetch_posts, format_num, format_url, param, prefs, request, rewrite_url, val, Post, Preferences, Subreddit};
use actix_web::{HttpRequest, HttpResponse, Result}; use actix_web::{HttpRequest, HttpResponse, Result};
use askama::Template; use askama::Template;
@ -11,7 +11,7 @@ struct SubredditTemplate {
posts: Vec<Post>, posts: Vec<Post>,
sort: (String, String), sort: (String, String),
ends: (String, String), ends: (String, String),
layout: String, prefs: Preferences,
} }
#[derive(Template)] #[derive(Template)]
@ -41,7 +41,7 @@ pub async fn page(req: HttpRequest) -> HttpResponse {
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"), prefs: prefs(req),
} }
.render() .render()
.unwrap(); .unwrap();

View File

@ -1,5 +1,5 @@
// CRATES // CRATES
use crate::utils::{cookie, error, fetch_posts, format_url, nested_val, param, request, Post, User}; use crate::utils::{error, fetch_posts, format_url, nested_val, param, prefs, request, Post, Preferences, User};
use actix_web::{HttpRequest, HttpResponse, Result}; use actix_web::{HttpRequest, HttpResponse, Result};
use askama::Template; use askama::Template;
use time::OffsetDateTime; use time::OffsetDateTime;
@ -12,7 +12,7 @@ struct UserTemplate {
posts: Vec<Post>, posts: Vec<Post>,
sort: (String, String), sort: (String, String),
ends: (String, String), ends: (String, String),
layout: String, prefs: Preferences,
} }
// FUNCTIONS // FUNCTIONS
@ -35,7 +35,7 @@ pub async fn profile(req: HttpRequest) -> HttpResponse {
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"), prefs: prefs(req),
} }
.render() .render()
.unwrap(); .unwrap();
@ -51,29 +51,25 @@ async fn user(name: &str) -> Result<User, &'static str> {
// Build the Reddit JSON API path // Build the Reddit JSON API path
let path: String = format!("user/{}/about.json", name); let path: String = format!("user/{}/about.json", name);
let res;
// 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) => { Ok(res) => {
res = response; // Grab creation date as unix timestamp
let created: i64 = res["data"]["created"].as_f64().unwrap_or(0.0).round() as i64;
// Parse the JSON output into a User struct
Ok(User {
name: name.to_string(),
title: nested_val(&res, "subreddit", "title"),
icon: format_url(nested_val(&res, "subreddit", "icon_img")),
karma: res["data"]["total_karma"].as_i64().unwrap_or(0),
created: OffsetDateTime::from_unix_timestamp(created).format("%b %d '%y"),
banner: nested_val(&res, "subreddit", "banner_img"),
description: nested_val(&res, "subreddit", "public_description"),
})
} }
// 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),
} }
// Grab creation date as unix timestamp
let created: i64 = res["data"]["created"].as_f64().unwrap_or(0.0).round() as i64;
// Parse the JSON output into a User struct
Ok(User {
name: name.to_string(),
title: nested_val(&res, "subreddit", "title"),
icon: format_url(nested_val(&res, "subreddit", "icon_img")),
karma: res["data"]["total_karma"].as_i64().unwrap_or(0),
created: OffsetDateTime::from_unix_timestamp(created).format("%b %d '%y"),
banner: nested_val(&res, "subreddit", "banner_img"),
description: nested_val(&res, "subreddit", "public_description"),
})
} }

View File

@ -1,7 +1,3 @@
// use std::collections::HashMap;
use std::collections::HashMap;
// //
// CRATES // CRATES
// //
@ -10,9 +6,9 @@ use askama::Template;
use base64::encode; use base64::encode;
use regex::Regex; use regex::Regex;
use serde_json::from_str; use serde_json::from_str;
use std::collections::HashMap;
use time::OffsetDateTime; use time::OffsetDateTime;
use url::Url; use url::Url;
// use surf::{client, get, middleware::Redirect};
// //
// STRUCTS // STRUCTS
@ -96,10 +92,23 @@ pub struct ErrorTemplate {
pub message: String, pub message: String,
} }
pub struct Preferences {
pub layout: String,
pub hide_nsfw: String,
}
// //
// FORMATTING // FORMATTING
// //
// Build preferences from cookies
pub fn prefs(req: actix_web::HttpRequest) -> Preferences {
Preferences {
layout: cookie(req.to_owned(), "layout"),
hide_nsfw: cookie(req, "hide_nsfw"),
}
}
// Grab a query param from a url // Grab a query param from a url
pub fn param(path: &str, value: &str) -> String { pub fn param(path: &str, value: &str) -> String {
let url = Url::parse(format!("https://libredd.it/{}", path).as_str()).unwrap(); let url = Url::parse(format!("https://libredd.it/{}", path).as_str()).unwrap();
@ -114,7 +123,7 @@ pub fn cookie(req: actix_web::HttpRequest, name: &str) -> String {
// Direct urls to proxy if proxy is enabled // Direct urls to proxy if proxy is enabled
pub fn format_url(url: String) -> String { pub fn format_url(url: String) -> String {
if url.is_empty() || url == "self" || url == "default" || url == "nsfw" { if url.is_empty() || url == "self" || url == "default" || url == "nsfw" || url == "spoiler" {
String::new() String::new()
} else { } else {
format!("/proxy/{}", encode(url).as_str()) format!("/proxy/{}", encode(url).as_str())
@ -129,10 +138,10 @@ pub fn rewrite_url(text: &str) -> String {
// Append `m` and `k` for millions and thousands respectively // Append `m` and `k` for millions and thousands respectively
pub fn format_num(num: i64) -> String { pub fn format_num(num: i64) -> String {
if num > 1000000 { if num > 1_000_000 {
format!("{}m", num / 1000000) format!("{}m", num / 1_000_000)
} else if num > 1000 { } else if num > 1000 {
format!("{}k", num / 1000) format!("{}k", num / 1_000)
} else { } else {
num.to_string() num.to_string()
} }
@ -279,9 +288,9 @@ pub async fn request(path: &str) -> Result<serde_json::Value, &'static str> {
} }
} }
// If can't send request to Reddit, return this to user // If can't send request to Reddit, return this to user
Err(e) => { Err(_e) => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(format!("{} - {}", url, e)); dbg!(format!("{} - {}", url, _e));
Err("Couldn't send request to Reddit") Err("Couldn't send request to Reddit")
} }
} }

View File

@ -3,7 +3,7 @@
{% block title %}Libreddit: search results - {{ params.q }}{% endblock %} {% block title %}Libreddit: search results - {{ params.q }}{% endblock %}
{% block layout %}{% if layout != "" %}{{ layout }}{% endif %}{% endblock %} {% block layout %}{% if prefs.layout != "" %}{{ prefs.layout }}{% endif %}{% endblock %}
{% block content %} {% block content %}
<div id="column_one"> <div id="column_one">
@ -22,7 +22,9 @@
</select>{% endif %}<input id="sort_submit" type="submit" value="&rarr;"> </select>{% endif %}<input id="sort_submit" type="submit" value="&rarr;">
</form> </form>
{% for post in posts %} {% for post in posts %}
{% if post.title != "Comment" %}
{% if post.flags.nsfw && prefs.hide_nsfw == "on" %}
{% else if post.title != "Comment" %}
<div class="post"> <div class="post">
<div class="post_left"> <div class="post_left">
<p class="post_score">{{ post.score }}</p> <p class="post_score">{{ post.score }}</p>

View File

@ -23,6 +23,10 @@
{% call utils::options(comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %} {% call utils::options(comment_sort, ["confidence", "top", "new", "controversial", "old"], "confidence") %}
</select> </select>
</div> </div>
<div id="hide_nsfw">
<label for="hide_nsfw">Hide NSFW posts:</label>
<input type="checkbox" name="hide_nsfw" {% if hide_nsfw == "on" %}checked{% endif %}>
</div>
</div> </div>
<input id="save" type="submit" value="Save"> <input id="save" type="submit" value="Save">
</form> </form>

View File

@ -11,7 +11,7 @@
{% 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 layout %}{% if prefs.layout != "" %}{{ prefs.layout }}{% endif %}{% endblock %}
{% block body %} {% block body %}
<main> <main>
@ -29,7 +29,10 @@
<input id="sort_submit" type="submit" value="&rarr;"> <input id="sort_submit" type="submit" value="&rarr;">
</select>{% endif %} </select>{% endif %}
</form> </form>
<div id="posts">
{% for post in posts %} {% for post in posts %}
{% if !(post.flags.nsfw && prefs.hide_nsfw == "on") %}
<div class="post {% if post.flags.stickied %}stickied{% endif %}"> <div class="post {% if post.flags.stickied %}stickied{% endif %}">
<div class="post_left"> <div class="post_left">
<p class="post_score">{{ post.score }}</p> <p class="post_score">{{ post.score }}</p>
@ -53,14 +56,16 @@
</div> </div>
<!-- POST MEDIA/THUMBNAIL --> <!-- POST MEDIA/THUMBNAIL -->
{% if layout == "card" && post.post_type == "image" %} {% if prefs.layout == "card" && post.post_type == "image" %}
<img class="post_media" src="{{ post.media }}"/> <img class="post_media" src="{{ post.media }}"/>
{% else if layout != "card" %} {% else if prefs.layout != "card" %}
<img class="post_thumbnail" src="{{ post.thumbnail }}"> <img class="post_thumbnail" src="{{ post.thumbnail }}">
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endif %}
{% endfor %} {% endfor %}
</div>
<footer> <footer>
{% if ends.0 != "" %} {% if ends.0 != "" %}

View File

@ -7,7 +7,7 @@
{% 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 layout %}{% if prefs.layout != "" %}{{ prefs.layout }}{% endif %}{% endblock %}
{% block body %} {% block body %}
<main style="max-width: 1000px;"> <main style="max-width: 1000px;">
@ -19,8 +19,12 @@
{% call utils::options(sort.1, ["hour", "day", "week", "month", "year", "all"], "all") %} {% call utils::options(sort.1, ["hour", "day", "week", "month", "year", "all"], "all") %}
</select>{% endif %}<input id="sort_submit" type="submit" value="&rarr;"> </select>{% endif %}<input id="sort_submit" type="submit" value="&rarr;">
</form> </form>
<div id="posts">
{% for post in posts %} {% for post in posts %}
{% if post.title != "Comment" %}
{% if post.flags.nsfw && prefs.hide_nsfw == "on" %}
{% else if post.title != "Comment" %}
<div class="post"> <div class="post">
<div class="post_left"> <div class="post_left">
<p class="post_score">{{ post.score }}</p> <p class="post_score">{{ post.score }}</p>
@ -47,9 +51,9 @@
</div> </div>
<!-- POST MEDIA/THUMBNAIL --> <!-- POST MEDIA/THUMBNAIL -->
{% if layout == "card" && post.post_type == "image" %} {% if prefs.layout == "card" && post.post_type == "image" %}
<img class="post_media" src="{{ post.media }}"/> <img class="post_media" src="{{ post.media }}"/>
{% else if layout != "card" %} {% else if prefs.layout != "card" %}
<img class="post_thumbnail" src="{{ post.thumbnail }}"> <img class="post_thumbnail" src="{{ post.thumbnail }}">
{% endif %} {% endif %}
</div> </div>
@ -69,7 +73,10 @@
</details> </details>
</div> </div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div>
<footer> <footer>
{% if ends.0 != "" %} {% if ends.0 != "" %}
<a href="?sort={{ sort.0 }}&before={{ ends.0 }}">PREV</a> <a href="?sort={{ sort.0 }}&before={{ ends.0 }}">PREV</a>