pub use hotaru::prelude::*;
pub use hotaru::http::*;
pub use std::env;
use crate::user;
use crate::user::User;
pub use crate::APP;
static NAVBAR: Lazy<Value> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/op/navbar.json");
Value::from_jsonf(path.to_str().unwrap()).unwrap_or(Value::None)
});
static FOOTER: Lazy<Value> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/op/footer.json");
Value::from_jsonf(path.to_str().unwrap()).unwrap_or(Value::None)
});
static SUPPORT_LANG: Lazy<Value> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/op/support_lang.json");
Value::from_jsonf(path.to_str().unwrap()).unwrap_or(Value::None)
});
static L10N: Lazy<Value> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/op/l10n.json");
Value::from_jsonf(path.to_str().unwrap()).unwrap_or(Value::None)
});
static ADMINS : Lazy<Value> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/admin_info/admins.json");
Value::from_jsonf(path.to_str().unwrap()).unwrap_or(Value::None)
});
static TRUSTED_ORIGIN : Lazy<Value> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/op/hosts.json");
Value::from_jsonf(path.to_str().unwrap()).unwrap_or(Value::None)
});
pub static BINDING: Lazy<String> = Lazy::new(|| {
let mut path = env::current_dir().unwrap();
path.push("programfiles/op/binding.txt");
std::fs::read_to_string(path)
.unwrap_or_else(|_| "localhost:3003".to_string())
});
static LOCALHOST: &str = "local";
const DEFAULT_ROBOTS: &str = "User-agent: *\nDisallow: /user/\nDisallow: /admin/\n";
pub fn pageprop_with_keywords(
req: &mut HttpReqCtx,
title: &str,
description: &str,
keywords: &str,
) -> Value {
let lang = lang(req);
let user_value: Value = req.params.get::<User>().unwrap().clone().into();
let path = req.path();
object!({
lang: &lang,
title: title,
color: "pink",
description: description,
keywords: keywords,
nav: NAVBAR.get(&lang).clone(),
foot: FOOTER.get(&lang).clone(),
user: user_value,
path: path,
})
}
pub fn pageprop(req: &mut HttpReqCtx, title: &str, description: &str) -> Value {
pageprop_with_keywords(req, title, description, "")
}
pub fn forbidden_response(req: &mut HttpReqCtx, message: Option<&str>) -> HttpResponse {
let current = req.request.meta.url();
let next = hotaru_lib::url_encoding::encode_url_owned(¤t);
akari_render!(
"user/forbidden.html",
pageprop = pageprop(req, "Forbidden", ""),
message = message.unwrap_or("You don't have permission to access this resource."),
next = next,
).status(StatusCode::FORBIDDEN)
}
pub fn default_lang() -> String {
SUPPORT_LANG.idx(0).string()
}
pub fn is_trusted(host: String) -> bool {
TRUSTED_ORIGIN
.list()
.iter()
.any(|v| v.string() == host || v.string() == LOCALHOST)
}
pub fn get_host() -> &'static Value {
return &TRUSTED_ORIGIN
}
pub fn get_default_host() -> String {
return TRUSTED_ORIGIN.idx(0).string()
}
pub fn get_admin() -> &'static Value {
return &ADMINS
}
pub async fn get_user(req: &mut HttpReqCtx) -> User {
user::fetch::get_user(req).await
}
pub async fn get_user_id(req: &mut HttpReqCtx) -> user::UserID {
user::fetch::get_user_id(req).await
}
middleware! {
pub RedirectGuest <HTTP> {
let user = get_user_id(&mut req).await;
if user.is_guest() {
req.response = redirect_response("/user/login");
return Ok(req)
} else {
next(req).await
}
}
}
middleware! {
pub UnauthGuest <HTTP> {
let user = get_user_id(&mut req).await;
if user.is_guest() {
req.response = json_response(object!({
success: false,
message: "Unauthorized"
}));
return Ok(req)
} else {
next(req).await
}
}
}
pub use crate::admin::RedirectNonAdmin;
pub fn lang(req: &mut HttpReqCtx) -> String {
lang_or_none(req).unwrap_or_else(default_lang)
}
pub fn lang_or_none(req: &mut HttpReqCtx) -> Option<String> {
if let Some(q) = req.query("lang") {
if SUPPORT_LANG.contains(&q.clone().into()) {
return Some(q);
}
}
if let Some(c) = req.get_cookie("lang") {
let v = c.get_value().to_string();
if SUPPORT_LANG.contains(&v.clone().into()) {
return Some(v);
}
}
None
}
pub fn from(req: &mut HttpReqCtx) -> String {
let referer = match req.header_str("referer") {
Some(r) if !r.is_empty() => r.to_string(),
_ => return "/".to_string(),
};
if let Some(scheme_end) = referer.find("://") {
let after_scheme = &referer[scheme_end + 3..];
match after_scheme.find('/') {
Some(slash) => after_scheme[slash..].to_string(),
None => "/".to_string(),
}
} else if referer.starts_with('/') {
referer
} else {
"/".to_string()
}
}
pub type Path = Vec<(String, String)>;
pub fn into_path(req: &mut HttpReqCtx, path: Vec<&str>) -> Value {
let mut value = object!([]);
let mut path_seg = 0;
let mut current_path = "".to_string();
path.into_iter()
.for_each(|name| {
value.push(object!({
path: ¤t_path,
name: name
}));
current_path = format!("{}/{}", current_path, req.segment(path_seg));
path_seg += 1;
});
let mut final_value = value.idx(value.len() - 1).clone();
final_value.set("path", req.path());
value.insert(value.len() - 1, final_value);
value
}
pub fn into_path_l(req: &mut HttpReqCtx, path: Vec<&str>) -> Value {
let lang = lang(req);
let localized: Vec<String> = path
.into_iter()
.map(|name| get_localized_string(name, &lang))
.collect();
let slices: Vec<&str> = localized.iter().map(String::as_str).collect();
into_path(req, slices)
}
pub fn get_localized_string(key: &str, lang: &str) -> String {
let dict = L10N.get(key);
match dict.try_get(lang) {
Ok(value) => value.string(),
Err(hotaru::akari::ValueError::KeyNotFoundError) => {
dict.get(default_lang()).string()
},
Err(_) => dict.string(),
}
}
endpoint! {
APP.url("/op/lang/<lang>"),
pub change_language <HTTP> {
let lang = req.param("lang").unwrap_or_else(default_lang);
redirect_response(&from(req)).add_cookie(
"lang",
Cookie::new(lang)
.path("/")
.http_only(true)
)
}
}
endpoint! {
APP.url("/static/<**path>"),
pub static_file <HTTP> {
println!("templates{}", req.path());
serve_static_file(&req.path()[1..])
}
}
endpoint! {
APP.url("/redirect"),
pub redirect <HTTP> {
let url = req.query("url").unwrap_or_else(|| "/".to_string());
println!("Redirecting to: {}", url);
redirect_response(&url)
}
}
endpoint! {
APP.url("/robots.txt"),
pub robots_txt <HTTP> {
let _ = req;
let path = env::current_dir().unwrap_or_default()
.join("programfiles/op/robots.txt");
let body = std::fs::read_to_string(&path)
.unwrap_or_else(|_| DEFAULT_ROBOTS.to_string());
text_response(body)
}
}