Set subscriptions as default front page

This commit is contained in:
spikecodes 2021-01-30 20:18:57 -08:00
parent 9c58d23b41
commit 21d96e261f
No known key found for this signature in database
GPG Key ID: 004CECFF9B463BCB
7 changed files with 86 additions and 48 deletions

View File

@ -54,7 +54,7 @@ async fn main() -> std::io::Result<()> {
.wrap_fn(move |req, srv| { .wrap_fn(move |req, srv| {
let secure = req.connection_info().scheme() == "https"; let secure = req.connection_info().scheme() == "https";
let https_url = format!("https://{}{}", req.connection_info().host(), req.uri().to_string()); let https_url = format!("https://{}{}", req.connection_info().host(), req.uri().to_string());
srv.call(req).map(move |res: Result<ServiceResponse, _>| srv.call(req).map(move |res: Result<ServiceResponse, _>| {
if force_https && !secure { if force_https && !secure {
Ok(ServiceResponse::new( Ok(ServiceResponse::new(
res.unwrap().request().to_owned(), res.unwrap().request().to_owned(),
@ -63,16 +63,21 @@ async fn main() -> std::io::Result<()> {
} else { } else {
res res
} }
) })
}) })
// Append trailing slash and remove double slashes // Append trailing slash and remove double slashes
.wrap(middleware::NormalizePath::default()) .wrap(middleware::NormalizePath::default())
// Apply default headers for security // Apply default headers for security
.wrap(middleware::DefaultHeaders::new() .wrap(
.header("Referrer-Policy", "no-referrer") middleware::DefaultHeaders::new()
.header("X-Content-Type-Options", "nosniff") .header("Referrer-Policy", "no-referrer")
.header("X-Frame-Options", "DENY") .header("X-Content-Type-Options", "nosniff")
.header("Content-Security-Policy", "default-src 'none'; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none';")) .header("X-Frame-Options", "DENY")
.header(
"Content-Security-Policy",
"default-src 'none'; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none';",
),
)
// Default service in case no routes match // Default service in case no routes match
.default_service(web::get().to(|| utils::error("Nothing here".to_string()))) .default_service(web::get().to(|| utils::error("Nothing here".to_string())))
// Read static files // Read static files

View File

@ -24,26 +24,24 @@ pub async fn handler(web::Path(b64): web::Path<String>) -> Result<HttpResponse>
let decoded = decode(b64).map(|bytes| String::from_utf8(bytes).unwrap_or_default()); let decoded = decode(b64).map(|bytes| String::from_utf8(bytes).unwrap_or_default());
match decoded { match decoded {
Ok(media) => { Ok(media) => match Url::parse(media.as_str()) {
match Url::parse(media.as_str()) { Ok(url) => {
Ok(url) => { let domain = url.domain().unwrap_or_default();
let domain = url.domain().unwrap_or_default();
if domains.contains(&domain) { if domains.contains(&domain) {
Client::default().get(media.replace("&amp;", "&")).send().await.map_err(Error::from).map(|res| { Client::default().get(media.replace("&amp;", "&")).send().await.map_err(Error::from).map(|res| {
HttpResponse::build(res.status()) HttpResponse::build(res.status())
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400") .header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
.header("Content-Length", res.headers().get("Content-Length").unwrap().to_owned()) .header("Content-Length", res.headers().get("Content-Length").unwrap().to_owned())
.header("Content-Type", res.headers().get("Content-Type").unwrap().to_owned()) .header("Content-Type", res.headers().get("Content-Type").unwrap().to_owned())
.streaming(res) .streaming(res)
}) })
} else { } else {
Err(error::ErrorForbidden("Resource must be from Reddit")) Err(error::ErrorForbidden("Resource must be from Reddit"))
}
} }
_ => Err(error::ErrorBadRequest("Can't parse base64 into URL")),
} }
} _ => Err(error::ErrorBadRequest("Can't parse base64 into URL")),
},
_ => Err(error::ErrorBadRequest("Can't decode base64")), _ => Err(error::ErrorBadRequest("Can't decode base64")),
} }
} }

View File

@ -26,25 +26,44 @@ struct WikiTemplate {
// 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 subscribed = cookie(&req, "subscriptions");
let default = cookie(&req, "front_page"); let front_page = cookie(&req, "front_page");
let sort = req.match_info().get("sort").unwrap_or("hot").to_string();
let sub = req let sub = req
.match_info() .match_info()
.get("sub") .get("sub")
.unwrap_or(if default.is_empty() { "popular" } else { default.as_str() }) .map(String::from)
.to_string(); .unwrap_or(if front_page == "default" || front_page.is_empty() {
let sort = req.match_info().get("sort").unwrap_or("hot").to_string(); if subscribed.is_empty() {
"popular".to_string()
} else {
subscribed.to_owned()
}
} else {
front_page.to_owned()
});
let path = format!("/r/{}.json?{}", sub, req.query_string());
match fetch_posts(&path, String::new()).await { match fetch_posts(&path, String::new()).await {
Ok((posts, after)) => { Ok((posts, after)) => {
// If you can get subreddit posts, also request subreddit metadata // If you can get subreddit posts, also request subreddit metadata
let sub = if !sub.contains('+') && sub != "popular" && sub != "all" { let sub = if !sub.contains('+') && sub != subscribed && sub != "popular" && sub != "all" {
// Regular subreddit
subreddit(&sub).await.unwrap_or_default() subreddit(&sub).await.unwrap_or_default()
} else if sub.contains('+') { } else if sub.contains('+') {
// Multireddit
Subreddit { Subreddit {
name: sub, name: sub,
..Subreddit::default() ..Subreddit::default()
} }
} else if sub == subscribed {
if req.path().starts_with("/r/") {
subreddit(&sub).await.unwrap_or_default()
} else {
Subreddit::default()
}
} else { } else {
Subreddit::default() Subreddit::default()
}; };
@ -84,11 +103,13 @@ pub async fn subscriptions(req: HttpRequest) -> HttpResponse {
if sub_list.is_empty() { if sub_list.is_empty() {
res.del_cookie(&Cookie::build("subscriptions", "").path("/").finish()); res.del_cookie(&Cookie::build("subscriptions", "").path("/").finish());
} else { } else {
res.cookie(Cookie::build("subscriptions", sub_list.join(",")) res.cookie(
.path("/") Cookie::build("subscriptions", sub_list.join("+"))
.http_only(true) .path("/")
.expires(OffsetDateTime::now_utc() + Duration::weeks(52)) .http_only(true)
.finish(),); .expires(OffsetDateTime::now_utc() + Duration::weeks(52))
.finish(),
);
} }
// Redirect back to subreddit // Redirect back to subreddit

View File

@ -145,7 +145,7 @@ pub fn prefs(req: HttpRequest) -> Preferences {
wide: cookie(&req, "wide"), wide: cookie(&req, "wide"),
hide_nsfw: cookie(&req, "hide_nsfw"), hide_nsfw: cookie(&req, "hide_nsfw"),
comment_sort: cookie(&req, "comment_sort"), comment_sort: cookie(&req, "comment_sort"),
subs: cookie(&req, "subscriptions").split(",").map(String::from).filter(|s| s != "").collect(), subs: cookie(&req, "subscriptions").split('+').map(String::from).filter(|s| s != "").collect(),
} }
} }

View File

@ -95,13 +95,23 @@ nav {
nav * { color: var(--text); } nav * { color: var(--text); }
nav #reddit, #code { color: var(--accent); } nav #reddit, #code { color: var(--accent); }
nav #logo { grid-area: logo; } nav #logo { grid-area: logo; }
nav #links { grid-area: links; }
nav #version { opacity: 50%; vertical-align: -2px; } nav #links {
nav #libreddit { vertical-align: -2px; } grid-area: links;
margin-left: 10px;
}
nav #version {
opacity: 50%;
vertical-align: -2px;
margin-right: 10px;
}
nav #libreddit {
vertical-align: -2px;
}
#settings_link { #settings_link {
margin-left: 10px;
opacity: 0.8; opacity: 0.8;
} }
@ -240,17 +250,18 @@ aside {
margin-top: 20px; margin-top: 20px;
} }
#sub_subscription > a { #sub_subscription button {
padding: 10px 20px; padding: 10px 20px;
border-radius: 5px; border-radius: 5px;
cursor: pointer;
} }
#sub_subscription > .add { #subscribe {
color: var(--foreground); color: var(--foreground);
background-color: var(--accent); background-color: var(--accent);
} }
#sub_subscription > .remove { #unsubscribe {
color: var(--text); color: var(--text);
background-color: var(--highlighted); background-color: var(--highlighted);
} }
@ -266,11 +277,10 @@ aside {
box-sizing: border-box; box-sizing: border-box;
font-size: 15px; font-size: 15px;
display: inline-block; display: inline-block;
margin-left: 10px;
} }
#subscriptions > summary { #subscriptions > summary {
padding: 10px 20px 10px 15px; padding: 8px 15px;
} }
#sub_list { #sub_list {

View File

@ -21,7 +21,7 @@
<div id="front_page"> <div id="front_page">
<label for="front_page">Front page:</label> <label for="front_page">Front page:</label>
<select name="front_page"> <select name="front_page">
{% call utils::options(prefs.front_page, ["popular", "all"], "popular") %} {% call utils::options(prefs.front_page, ["default", "popular", "all"], "default") %}
</select> </select>
</div> </div>
<div id="layout"> <div id="layout">

View File

@ -127,9 +127,13 @@
</div> </div>
<div id="sub_subscription"> <div id="sub_subscription">
{% if prefs.subs.contains(sub.name) %} {% if prefs.subs.contains(sub.name) %}
<a href="/r/{{ sub.name }}/unsubscribe" class="subscribe remove">Unsubscribe</a> <form action="/r/{{ sub.name }}/unsubscribe">
<button id="unsubscribe">Unsubscribe</button>
</form>
{% else %} {% else %}
<a href="/r/{{ sub.name }}/subscribe" class="subscribe add">Subscribe</a> <form action="/r/{{ sub.name }}/subscribe">
<button id="subscribe">Subscribe</button>
</form>
{% endif %} {% endif %}
</div> </div>
</div> </div>