caracal 0.3.6

Nostr client for Gemini
use super::route_prelude::*;
use crate::nostru;

#[derive(Template)]
#[template(path = "dm_conversation.gmi", escape = "txt")]
pub struct ConversationTemplate {
    pub rumors: Vec<UnsignedEvent>,
}

#[derive(Template)]
#[template(path = "dm_history.gmi", escape = "txt")]
pub struct DmHistoryTemplate {
    pub rumors: Vec<(UnsignedEvent, Option<Metadata>)>,
}

pub async fn person_send_dm(ctx: RouteContext) -> Response {
    let params = ctx.parameters.clone();

    let Some(user) = ugate(ctx.certificate).await else {
        return resp_nocert();
    };

    let Some(npub) = params.get("npub") else {
        return resp_invalid_params();
    };

    let Ok(pubkey) = PublicKey::parse(npub) else {
        return resp_invalid_params();
    };

    if let Some(text) = dec_urlq(&ctx.url) {
        match user.client.send_private_msg(pubkey, text, []).await {
            Ok(_) => Response::success("Sent !"),
            Err(err) => Response::temporary_failure(format!("{err}")),
        }
    } else {
        Response::input(t!("dm_prompt"))
    }
}

pub async fn person_dm_conversation(
    ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let params = ctx.parameters.clone();

    let Some(npub) = params.get("npub") else {
        return resp_invalid_params();
    };

    let Ok(pubkey) = PublicKey::parse(npub) else {
        return resp_invalid_params();
    };

    let sub = Filter::new()
        .kind(Kind::GiftWrap)
        .pubkey(user.signer.get_public_key().await.unwrap());

    let Ok(events) =
        user.client.fetch_events(sub, Duration::from_secs(10)).await
    else {
        return Response::temporary_failure("ERR");
    };

    let mut rumors: Vec<UnsignedEvent> = Vec::new();

    for ev in events {
        let Ok(UnwrappedGift { rumor, sender }) =
            user.client.unwrap_gift_wrap(&ev).await
        else {
            continue;
        };

        if sender != pubkey {
            continue;
        }

        if rumor.kind == Kind::PrivateDirectMessage {
            rumors.push(rumor);
        }
    }

    Response::success(WindTemplate::render(ConversationTemplate { rumors }))
}

pub async fn dm_all(
    _ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let sub = Filter::new()
        .kind(Kind::GiftWrap)
        .pubkey(user.signer.get_public_key().await.unwrap());

    let Ok(events) =
        user.client.fetch_events(sub, Duration::from_secs(3)).await
    else {
        return Response::temporary_failure("ERR");
    };

    let mut rumors = Vec::new();

    for event in events {
        let Ok(UnwrappedGift { rumor, sender }) =
            user.client.unwrap_gift_wrap(&event).await
        else {
            continue;
        };

        let metadata = nostru::fetch_user_metadata(&user.client, sender).await;

        if rumor.kind == Kind::PrivateDirectMessage {
            rumors.push((rumor, metadata));
        }
    }

    Response::success(WindTemplate::render(DmHistoryTemplate { rumors }))
}