caracal 0.2.7

Nostr client for Gemini
use crate::aska::WindTemplate;
use crate::user::CaracalUser;
use askama::Template;
use nostr_sdk::prelude::*;
use rust_i18n::t;
use windmark_titanesque::{context::RouteContext, response::Response};

#[derive(Template, Clone)]
#[template(path = "nostriches_list.gmi", escape = "txt")]
struct UserListTemplate {
    meta_events: Events,
}

#[derive(Template, Clone)]
#[template(path = "nostriches_search.gmi", escape = "txt")]
struct UserSearchTemplate {
    meta_events: Events,
}

pub async fn nostriches_list(
    _ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let meta_filter = Filter::new().kind(Kind::Metadata);

    let Ok(meta_events) = user.client.database().query(meta_filter).await
    else {
        return Response::temporary_failure("db");
    };

    Response::success(WindTemplate::render(UserListTemplate { meta_events }))
}

pub async fn nostriches_search(
    ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let Some(input) = ctx.url.query() else {
        return Response::input(t!("input_nostr_name"));
    };
    let Ok(input) = urlencoding::decode(input) else {
        return Response::input(t!("input_nostr_name"));
    };

    let meta_filter = Filter::new().kind(Kind::Metadata);

    let Ok(all_meta) = user.client.database().query(meta_filter).await else {
        return Response::temporary_failure("db");
    };

    let events = all_meta
        .iter()
        .filter_map(|ev| {
            if let Ok(meta) = Metadata::try_from(ev) {
                Some((ev, meta))
            } else {
                None
            }
        })
        .filter_map(|(ev, meta)| {
            if let Some(name) = meta.name
                && name.contains(&input.to_string())
            {
                Some(ev.clone())
            } else {
                None
            }
        });

    Response::success(WindTemplate::render(UserSearchTemplate {
        meta_events: Events::from_iter(events),
    }))
}