use crate::{config, pages}; use actix_web::http::header; use actix_web::web::Form; use actix_web::{get, post, web, Error, HttpRequest, HttpResponse, Responder, Result}; use maud::{html, PreEscaped}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub struct MessageForm { msg_name: String, message: String, } #[post("/message")] pub async fn message_post(r: HttpRequest, f: Form) -> impl Responder { let config: &web::Data = r.app_data().expect("get config failed"); crate::msg::save_message(&f.message, &f.msg_name.to_string()); crate::notification::notify(&f.message, &f.msg_name, config.clone()).await; web_base::func::redirect("/message") } #[get("/message")] pub async fn message_page(r: HttpRequest) -> impl Responder { let config: &web::Data = r.app_data().expect("get config failed"); let resp = html! { div class="container" style="margin-top: 25px" { h1 { "Message" }; br; form action=(web_base::func::get_full_url(&r)) method="post" autocomplete="off" { input value="" type="text" required name="msg_name" placeholder="Name" class="form-control bg-dark text-white" style="margin-bottom: 15px"; textarea placeholder="Message" required name="message" cols="10" rows="10" class="form-control bg-dark text-white" style="margin-bottom: 15px;" {}; input value="Send Message" type="submit" required name="submit" class="btn btn-danger text-white text-decoration-none"; } } }; pages::html_fn::build_site(resp.into_string(), "Message", false, true, config, &r).await } #[get("/mirrors.txt")] pub async fn mirrors(r: HttpRequest) -> Result { let config: &web::Data = r.app_data().expect("get config failed"); if let Ok(mirror_file) = std::fs::File::open("./config/mirrors.txt") { let content = std::io::read_to_string(mirror_file).expect("could not read file"); if web_base::func::is_browser(&r) { let resp = html! { div style="margin: 25px;" { pre { (content) }; } }; return Ok(pages::html_fn::build_site( resp.into_string(), "Mirrors", false, true, config, &r, ) .await); } return HttpResponse::Ok().message_body(content); } HttpResponse::NotFound().message_body(String::new()) } #[get("/public_key")] pub async fn public_key(r: HttpRequest) -> Result { if web_base::func::is_browser(&r) { let config: &web::Data = r.app_data().expect("get config failed"); let host = format!("http://{}", web_base::func::get_host(&r)); let key = std::io::read_to_string( std::fs::File::open("./config/pub.key").expect("key could not be opened"), ) .expect("could not read key"); let pgp = gnupg_rs::GnuPG::new().expect("no gpg"); let key_name = pgp.import_key(&key).expect("key not valid").name; let key = key.replace('\n', "
"); let resp = html! { div class="container" style="margin-top: 25px" { div class="alert alert-info" { b { "To Import: " }; span style="display: block;font-family: monospace,monospace;margin-top: 10px; font-size: 20px;overflow-wrap: break-word;" { (format!("curl -sL \"{host}/public_key\"|gpg --import")) }; }; h4 class="container card" style="padding-top: 10px; padding-bottom: 10px; background: black; margin-bottom: 15px;" { (key_name) }; }; div class="container card bg-primary" { p { (PreEscaped(key)) } } }; return Ok(pages::html_fn::build_site( resp.into_string(), "Public Key", true, false, config, &r, ) .await); } if let Ok(key_f) = std::fs::File::open("./config/pub.key") { if let Ok(key_data) = std::io::read_to_string(key_f) { return HttpResponse::Ok() .insert_header(header::ContentType::plaintext()) .message_body(key_data); } } HttpResponse::NotFound().message_body(String::new()) } fn build_information_block(conf: &web::Data) -> String { let name = conf.name().expect("no name found"); html! { div class="container border-dark" style="margin-top: 20px" { img src="/assets/me" height="200" width="200" alt="Me" class="rounded"; br;br; h1 { (name) }; hr; } } .into_string() } fn build_contact_block(conf: &web::Data) -> String { conf.email().map_or_else(String::new, |email| { let pgp_key_message = if std::path::Path::new("./config/pub.key").exists() { html! { a href="/public_key" { "My PGP Key" }; br; a href="/message" { "Write a message" }; br;br; } .into_string() } else { String::new() }; html! { div class="container border-dark" { h1 { span class="bi bi-person-lines-fill" style="vertical-align: middle;"; span { "Contact" }; }; hr; (PreEscaped(pgp_key_message)); a href=(format!("mailto:{email}")) { (email) }; hr; } } .into_string() }) } fn build_donation_block(conf: &web::Data) -> String { conf.xmr_address().map_or_else(String::new, |xmr_addr| { html! { div class="container" style="margin-top: 20px" { h1 { span class="bi bi-cash-coin"; span { "Donation" }; }; hr; p { b { "Monero: " }; span style="color: orange;overflow-wrap: break-word;" { (xmr_addr) }; } } } .into_string() }) } #[get("/")] pub(crate) async fn index(conf: web::Data, r: HttpRequest) -> impl Responder { let information_block = build_information_block(&conf); let contact_block = build_contact_block(&conf); let donation_block = build_donation_block(&conf); let own_index = std::fs::read_to_string("./config/index.html").unwrap_or_default(); let content = format!( " {information_block} {contact_block} {own_index} {donation_block} " ); crate::pages::html_fn::build_site(content, "About Me", false, true, &conf, &r).await }