use super::route_prelude::*;
use crate::nostru;
use regex::Regex;
#[derive(Template)]
#[template(path = "profile_index.gmi", escape = "txt")]
pub struct MyProfileTemplate {
url: Url,
npub: String,
metadata: Option<Metadata>,
}
#[derive(Template)]
#[template(path = "profile_start.gmi", escape = "txt")]
pub struct ProfileStartTemplate {}
pub async fn profile_init_reset(
_: RouteContext,
user: &'static mut CaracalUser,
) -> Response {
let default_meta = Metadata::new();
match user.client.set_metadata(&default_meta).await {
Ok(_event_id) => Response::temporary_redirect("/profile"),
Err(_error) => Response::temporary_failure("Error"),
}
}
pub async fn profile_index(
ctx: RouteContext,
user: &'static mut CaracalUser,
) -> Response {
let Ok(pubk) = user.public_key().await else {
return resp_signer_error();
};
let npub = pubk.to_bech32().unwrap();
match nostru::fetch_user_metadata(&user.client, pubk).await {
Some(metadata) => {
Response::success(WindTemplate::render(MyProfileTemplate {
url: ctx.url,
npub,
metadata: Some(metadata),
}))
}
None => {
Response::success(WindTemplate::render(ProfileStartTemplate {}))
}
}
}
pub async fn profile_edit(
ctx: RouteContext,
user: &'static mut CaracalUser,
) -> Response {
let Some(attr) = ctx.parameters.get("attr") else {
return resp_invalid_params();
};
let Some(value) = ctx.url.query() else {
let input_message = match attr {
"about" => t!("type_in_your_biography"),
"name" => t!("type_in_your_name"),
"website" => t!("type_in_your_website"),
"misfin" => t!("type_in_your_misfin_address"),
_ => format!("Type in the value for: {}", attr).into(),
};
return Response::input(input_message);
};
let value = decode(value).unwrap();
let Some(mut metadata) = nostru::fetch_user_metadata(
&user.client,
user.signer.get_public_key().await.unwrap(),
)
.await
else {
return resp_invalid_params();
};
match attr {
"about" => {
metadata.about = Some(value.into());
}
"name" => {
metadata.name = Some(value.into());
}
"nip05" => {
metadata.nip05 = Some(value.into());
}
"lud06" => {
metadata.lud06 = Some(value.into());
}
"lud16" => {
metadata.lud16 = Some(value.into());
}
"display_name" => {
metadata.display_name = Some(value.into());
}
"website" => {
if let Ok(url) = Url::parse(&value) {
metadata.website = Some(url.to_string());
}
}
"picture" => {
if let Ok(url) = Url::parse(&value) {
metadata.picture = Some(url.to_string());
}
}
"banner" => {
if let Ok(url) = Url::parse(&value) {
metadata.banner = Some(url.to_string());
}
}
"misfin" => {
let pattern = r"^[a-zA-Z0-9.%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$";
let regex = Regex::new(pattern).unwrap();
if regex.is_match(&value) {
metadata.custom.insert("misfin".to_string(), value.into());
} else {
return Response::temporary_failure(t!(
"invalid_misfin_address"
));
}
}
&_ => todo!(),
}
user.client.connect().await;
match user.client.set_metadata(&metadata).await {
Ok(_event_id) => Response::permanent_redirect("/profile"),
Err(_error) => Response::permanent_failure("Error updating metadata"),
}
}
pub async fn profile_titan_edit(
ctx: RouteContext,
user: &'static mut CaracalUser,
) -> Response {
let Some(attr) = ctx.parameters.get("attr") else {
return resp_invalid_params();
};
let Some(mut metadata) = nostru::fetch_user_metadata(
&user.client,
user.public_key().await.unwrap(),
)
.await
else {
return resp_invalid_params();
};
match ctx.titan_rsc {
Some(titan) => {
match attr {
"about" => {
if let Ok(text) = String::from_utf8(titan.content) {
metadata.about = Some(text);
}
}
&_ => (),
}
match user.client.set_metadata(&metadata).await {
Ok(_) => Response::temporary_redirect(format!(
"gemini://{}/profile",
ctx.url.authority()
)),
Err(_error) => {
Response::permanent_failure("Error updating metadata")
}
}
}
None => Response::temporary_failure("No Titan data"),
}
}
pub async fn profile_upload(
ctx: RouteContext,
user: &'static mut CaracalUser,
) -> Response {
let Some(obj) = ctx.parameters.get("object") else {
return resp_invalid_params();
};
let Some(rsc) = ctx.titan_rsc else {
return Response::temporary_failure("No file");
};
if let Ok(descriptor) = titan_to_blossom(rsc, user.signer.clone()).await {
let Some(metadata) = nostru::fetch_user_metadata(
&user.client,
user.signer.get_public_key().await.unwrap(),
)
.await
else {
return resp_invalid_params();
};
let metadata = if obj == "picture" {
metadata.picture(descriptor.url)
} else if obj == "banner" {
metadata.banner(descriptor.url)
} else {
metadata
};
match user.client.set_metadata(&metadata).await {
Ok(_event_id) => Response::temporary_redirect(format!(
"gemini://{}/profile",
ctx.url.authority()
)),
Err(_error) => {
Response::permanent_failure("Error updating metadata")
}
}
} else {
Response::temporary_failure(t!("blossom_error"))
}
}