caracal 0.2.0

Nostr client for Gemini
use std::time::Duration;

use crate::aska::WindTemplate;
use crate::routes::response::*;
use crate::routes::{humanize_ts, resp_nocert, ugate};

use nostr_sdk::prelude::*;

use askama::Template;
use windmark_titanesque::{context::RouteContext, response::Response};

use rust_i18n::t;

rust_i18n::i18n!("locales");

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

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) -> 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();
    };

    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 }))
}