caracal 0.2.0

Nostr client for Gemini
use nostr_sdk::prelude::*;
use std::time::Duration;
use windmark_titanesque::{context::RouteContext, response::Response};

use crate::nostru;
use crate::routes::t;
use crate::user::CaracalUser;

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

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

    let _meta = nostru::fetch_user_metadata(&user.client, pubk).await;

    let Ok(mut contact_list) =
        user.client.get_contact_list(Duration::from_secs(10)).await
    else {
        return Response::temporary_failure("Failed to fetch contact list");
    };

    contact_list.push(Contact::new(pubk));

    match user
        .client
        .send_event_builder(EventBuilder::contact_list(contact_list))
        .await
    {
        Ok(_) => {
            // Send a message so that the hook will resubscribe
            let _ = user.tx.send(0).await;

            // Redirect to the contact list page
            Response::temporary_redirect("/contacts")
        }
        Err(err) => Response::temporary_failure(format!(
            "Could not update contact list: {err}"
        )),
    }
}

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

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

    let Ok(mut contact_list) =
        user.client.get_contact_list(Duration::from_secs(10)).await
    else {
        return Response::temporary_failure("Failed to fetch contact list");
    };

    contact_list.retain(|contact| contact.public_key != pubk);

    match user
        .client
        .send_event_builder(EventBuilder::contact_list(contact_list))
        .await
    {
        Ok(_) => {
            let _ = user.tx.send(0).await;

            // Redirect to the contact list page
            Response::temporary_redirect("/contacts")
        }
        Err(_) => Response::temporary_failure("Could not update contact list"),
    }
}

pub async fn follow(ctx: RouteContext) -> Response {
    if let Some(npub) = ctx.url.query() {
        if let Ok(_key) = PublicKey::parse(npub) {
            Response::temporary_redirect(format!("/p/{}/follow", npub))
        } else {
            Response::input(t!("npub_input"))
        }
    } else {
        Response::input(t!("npub_input"))
    }
}