//! User embed handlers: tip button. use axum::{ extract::{Path, State}, response::{Html, IntoResponse, Response}, }; use crate::{ db::{self, Username}, error::{AppError, Result}, AppState, }; use super::item::set_embed_headers; #[tracing::instrument(skip_all, name = "embed::tip_button")] /// GET /embed/u/{username}/tip pub(super) async fn tip_button( State(state): State, Path(username): Path, ) -> Result { let username = Username::new(&username).map_err(|_| AppError::NotFound)?; let user = db::users::get_user_by_username(&state.db, &username) .await? .ok_or(AppError::NotFound)?; if user.is_suspended() || user.is_deactivated() || !user.tips_enabled { return Err(AppError::NotFound); } let display_name = user.display_name.as_deref().unwrap_or(&user.username); let tip_url = format!("{}/u/{}/tip", state.config.host_url, user.username); let avatar_html = user.avatar_url.as_ref() .map(|url| format!(r#""#, html_escape(url))) .unwrap_or(r#"
"#.to_string()); let html = format!( r#" Support {display_name} — Makenot.work
{avatar} Support @{username} Support
"#, display_name = html_escape(display_name), avatar = avatar_html, username = html_escape(&user.username), tip_url = tip_url, ); let mut response = Html(html).into_response(); set_embed_headers(&mut response); Ok(response) } fn html_escape(s: &str) -> String { s.replace('&', "&") .replace('<', "<") .replace('>', ">") .replace('"', """) }