caracal 0.4.1

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

#[derive(Template, Clone)]
#[template(path = "mute_list.gmi", escape = "txt")]
struct MuteListTemplate {
    mute_list: MuteList,
}

pub async fn get_mute_list(
    user: &'static CaracalUser,
) -> Result<MuteList, Box<dyn std::error::Error>> {
    let Ok(signer_pubk) = user.signer.get_public_key().await else {
        return Err(Box::from("Signer error"));
    };

    let Ok(events) = user
        .client
        .fetch_events(
            Filter::new().kind(Kind::MuteList).author(signer_pubk),
            Duration::from_secs(3),
        )
        .await
    else {
        return Err(Box::from("MuteList events fetch failed"));
    };

    let mut mute_list = MuteList::default();

    if let Some(event) = events.first() {
        mute_list.public_keys.extend(event.tags.public_keys());
        mute_list
            .hashtags
            .extend(event.tags.hashtags().map(str::to_string));
    }

    Ok(mute_list)
}

/// Mute a [`PublicKey`]
pub async fn person_mute(
    ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let npub = ctx.parameters.get("npub").unwrap();

    let Ok(pubk) = PublicKey::parse(npub) else {
        return Response::temporary_failure("Invalid pubkey");
    };

    let Ok(mut mute_list) = get_mute_list(user).await else {
        return Response::temporary_failure("fetch mute list error");
    };

    mute_list.public_keys.push(pubk);

    match user
        .client
        .send_event_builder(
            EventBuilder::mute_list(mute_list.clone()).dedup_tags(),
        )
        .await
    {
        Ok(_) => Response::success(WindTemplate::render(MuteListTemplate {
            mute_list,
        })),
        Err(_) => Response::temporary_failure("Fail"),
    }
}

/// Unmute a [`PublicKey`]
pub async fn person_unmute(
    ctx: RouteContext,
    user: &'static mut CaracalUser,
) -> Response {
    let npub = ctx.parameters.get("npub").unwrap();

    let Ok(pubk) = PublicKey::parse(npub) else {
        return Response::temporary_failure("Invalid pubkey");
    };

    let Ok(mut mute_list) = get_mute_list(user).await else {
        return Response::temporary_failure("fetch mute list error");
    };

    mute_list.public_keys.retain(|pubkey| *pubkey != pubk);

    match user
        .client
        .send_event_builder(
            EventBuilder::mute_list(mute_list.clone()).dedup_tags(),
        )
        .await
    {
        Ok(_) => Response::success(WindTemplate::render(MuteListTemplate {
            mute_list,
        })),
        Err(_) => Response::temporary_failure("Failed"),
    }
}