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-11-15 15:39:33 +13:00
|
|
|
url: String,
|
2021-01-06 15:04:49 +13:00
|
|
|
}
|
|
|
|
|
2021-05-10 13:25:52 +12:00
|
|
|
// CONSTANTS
|
|
|
|
|
2022-09-27 14:35:23 +13:00
|
|
|
const PREFS: [&str; 11] = [
|
2021-05-10 13:25:52 +12:00
|
|
|
"theme",
|
|
|
|
"front_page",
|
|
|
|
"layout",
|
|
|
|
"wide",
|
|
|
|
"comment_sort",
|
|
|
|
"post_sort",
|
|
|
|
"show_nsfw",
|
2022-09-27 14:35:23 +13:00
|
|
|
"blur_nsfw",
|
2021-05-10 13:25:52 +12:00
|
|
|
"use_hls",
|
|
|
|
"hide_hls_notification",
|
2021-10-26 17:27:55 +13:00
|
|
|
"autoplay_videos",
|
2021-05-10 13:25:52 +12:00
|
|
|
];
|
|
|
|
|
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-11-15 15:39:33 +13:00
|
|
|
let url = req.uri().to_string();
|
|
|
|
template(SettingsTemplate {
|
|
|
|
prefs: Preferences::new(req),
|
2021-11-15 15:51:36 +13:00
|
|
|
url,
|
2021-11-15 15:39:33 +13:00
|
|
|
})
|
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-02-10 06:38:52 +13:00
|
|
|
|
2021-05-21 07:24:06 +12:00
|
|
|
let mut response = redirect("/settings".to_string());
|
2021-01-06 15:04:49 +13:00
|
|
|
|
2021-05-10 13:25:52 +12: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(
|
2021-06-12 06:03:36 +12:00
|
|
|
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
|
|
|
}
|
2021-02-14 09:55:23 +13:00
|
|
|
|
2021-05-10 13:25:52 +12: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-02-14 09:55:23 +13:00
|
|
|
|
2021-03-18 11:30:33 +13:00
|
|
|
let form = url::form_urlencoded::parse(query).collect::<HashMap<_, _>>();
|
|
|
|
|
|
|
|
let path = match form.get("redirect") {
|
2021-05-10 13:25:52 +12:00
|
|
|
Some(value) => format!("/{}", value.replace("%26", "&").replace("%23", "#")),
|
2021-02-14 12:02:38 +13:00
|
|
|
None => "/".to_string(),
|
2021-02-14 09:55:23 +13:00
|
|
|
};
|
|
|
|
|
2021-05-21 07:24:06 +12:00
|
|
|
let mut response = redirect(path);
|
2021-02-14 09:55:23 +13:00
|
|
|
|
2021-11-26 17:02:04 +13:00
|
|
|
for name in [PREFS.to_vec(), vec!["subscriptions", "filters"]].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(
|
2021-06-12 06:03:36 +12:00
|
|
|
Cookie::build(name.to_owned(), value.clone())
|
2021-02-14 09:55:23 +13:00
|
|
|
.path("/")
|
|
|
|
.http_only(true)
|
|
|
|
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
|
|
|
.finish(),
|
|
|
|
),
|
2021-05-10 13:25:52 +12:00
|
|
|
None => {
|
|
|
|
if remove_cookies {
|
2021-09-10 12:28:55 +12:00
|
|
|
response.remove_cookie(name.to_string());
|
2021-05-10 13:25:52 +12:00
|
|
|
}
|
|
|
|
}
|
2021-02-14 09:55:23 +13:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-05-21 07:24:06 +12:00
|
|
|
response
|
2021-05-10 13:25:52 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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))
|
2021-02-14 09:55:23 +13:00
|
|
|
}
|