redsunlib/src/settings.rs

134 lines
3.2 KiB
Rust
Raw Normal View History

2021-03-18 11:30:33 +13:00
use std::collections::HashMap;
2021-01-06 15:04:49 +13:00
// CRATES
2021-03-18 11:30:33 +13:00
use crate::server::ResponseExt;
2021-02-25 18:29:23 +13:00
use crate::utils::{redirect, template, Preferences};
2021-01-06 15:04:49 +13:00
use askama::Template;
2021-03-18 11:30:33 +13:00
use cookie::Cookie;
use futures_lite::StreamExt;
use hyper::{Body, Request, Response};
2021-01-06 15:04:49 +13:00
use time::{Duration, OffsetDateTime};
// STRUCTS
#[derive(Template)]
2021-01-08 05:38:05 +13:00
#[template(path = "settings.html")]
2021-01-06 15:04:49 +13:00
struct SettingsTemplate {
2021-01-09 14:50:03 +13:00
prefs: Preferences,
2021-01-06 15:04:49 +13:00
}
// CONSTANTS
const PREFS: [&str; 9] = [
"theme",
"front_page",
"layout",
"wide",
"comment_sort",
"post_sort",
"show_nsfw",
"use_hls",
"hide_hls_notification",
];
2021-01-06 15:04:49 +13:00
// FUNCTIONS
// Retrieve cookies from request "Cookie" header
2021-03-18 11:30:33 +13:00
pub async fn get(req: Request<Body>) -> Result<Response<Body>, String> {
2021-02-25 18:29:23 +13:00
template(SettingsTemplate { prefs: Preferences::new(req) })
2021-01-06 15:04:49 +13:00
}
// Set cookies using response "Set-Cookie" header
2021-03-18 11:30:33 +13:00
pub async fn set(req: Request<Body>) -> Result<Response<Body>, String> {
// Split the body into parts
let (parts, mut body) = req.into_parts();
// Grab existing cookies
2021-05-21 07:24:06 +12:00
let _cookies: Vec<Cookie> = parts
.headers
.get_all("Cookie")
.iter()
.filter_map(|header| Cookie::parse(header.to_str().unwrap_or_default()).ok())
.collect();
2021-03-18 11:30:33 +13:00
// Aggregate the body...
// let whole_body = hyper::body::aggregate(req).await.map_err(|e| e.to_string())?;
let body_bytes = body
.try_fold(Vec::new(), |mut data, chunk| {
data.extend_from_slice(&chunk);
Ok(data)
})
.await
.map_err(|e| e.to_string())?;
let form = url::form_urlencoded::parse(&body_bytes).collect::<HashMap<_, _>>();
2021-05-21 07:24:06 +12:00
let mut response = redirect("/settings".to_string());
2021-01-06 15:04:49 +13:00
for &name in &PREFS {
2021-03-18 11:30:33 +13:00
match form.get(name) {
2021-05-21 07:24:06 +12:00
Some(value) => response.insert_cookie(
Cookie::build(name.to_owned(), value.clone())
2021-01-09 14:35:04 +13:00
.path("/")
.http_only(true)
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
.finish(),
),
2021-05-21 07:24:06 +12:00
None => response.remove_cookie(name.to_string()),
2021-01-09 14:35:04 +13:00
};
}
2021-01-08 05:38:05 +13:00
2021-05-21 07:24:06 +12:00
Ok(response)
2021-01-06 15:04:49 +13:00
}
fn set_cookies_method(req: Request<Body>, remove_cookies: bool) -> Response<Body> {
2021-03-18 11:30:33 +13:00
// Split the body into parts
let (parts, _) = req.into_parts();
// Grab existing cookies
2021-05-21 07:24:06 +12:00
let _cookies: Vec<Cookie> = parts
.headers
.get_all("Cookie")
.iter()
.filter_map(|header| Cookie::parse(header.to_str().unwrap_or_default()).ok())
.collect();
2021-03-18 11:30:33 +13:00
let query = parts.uri.query().unwrap_or_default().as_bytes();
2021-03-18 11:30:33 +13:00
let form = url::form_urlencoded::parse(query).collect::<HashMap<_, _>>();
let path = match form.get("redirect") {
Some(value) => format!("/{}", value.replace("%26", "&").replace("%23", "#")),
2021-02-14 12:02:38 +13:00
None => "/".to_string(),
};
2021-05-21 07:24:06 +12:00
let mut response = redirect(path);
2021-05-20 15:30:10 +12:00
for name in [PREFS.to_vec(), vec!["subscriptions"]].concat() {
2021-03-18 11:30:33 +13:00
match form.get(name) {
2021-05-21 07:24:06 +12:00
Some(value) => response.insert_cookie(
Cookie::build(name.to_owned(), value.clone())
.path("/")
.http_only(true)
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
.finish(),
),
None => {
if remove_cookies {
2021-09-10 12:28:55 +12:00
response.remove_cookie(name.to_string());
}
}
};
}
2021-05-21 07:24:06 +12:00
response
}
// Set cookies using response "Set-Cookie" header
pub async fn restore(req: Request<Body>) -> Result<Response<Body>, String> {
Ok(set_cookies_method(req, true))
}
pub async fn update(req: Request<Body>) -> Result<Response<Body>, String> {
Ok(set_cookies_method(req, false))
}