enigmatick 0.4.1

Enigmatick is a social media platform that integrates with servers that implement the ActivityPub protocol (e.g., Mastodon)
Documentation
use super::Inbox;
use crate::{
    db::runner::DbRunner,
    models::{
        activities::{
            create_activity, get_activity_by_ap_id, revoke_activity_by_apid, ActivityTarget,
            ActivityType, NewActivity,
        },
        follows::delete_follow,
    },
    runner::{self},
};
use deadpool_diesel::postgres::Pool;
use jdt_activity_pub::{ApActivity, ApAddress, ApUndo};
use reqwest::StatusCode;
use serde_json::Value;

impl Inbox for Box<ApUndo> {
    async fn inbox<C: DbRunner>(
        &self,
        conn: &C,
        pool: Pool,
        raw: Value,
    ) -> Result<StatusCode, StatusCode> {
        log::debug!("{:?}", self.clone());

        let target_ap_id = self.object.reference().ok_or_else(|| {
            log::warn!("Unable to determine Undo target Object");
            StatusCode::BAD_REQUEST
        })?;

        let (_, target_activity, _, _) = get_activity_by_ap_id(conn, target_ap_id.clone())
            .await
            .map_err(|_| StatusCode::NOT_FOUND)?
            .ok_or_else(|| {
                log::error!("Undo Activity not found");
                StatusCode::NOT_FOUND
            })?;

        let target_activity = target_activity.ok_or_else(|| {
            log::error!("Target Activity not found");
            StatusCode::NOT_FOUND
        })?;

        let activity_target = (
            ApActivity::Undo(self.clone()),
            Some(ActivityTarget::from(target_activity.clone())),
        );

        let activity = NewActivity::try_from(activity_target)
            .map_err(|e| {
                log::error!("Failed to build Activity: {e}");
                StatusCode::INTERNAL_SERVER_ERROR
            })?
            .set_raw(raw);

        create_activity(conn, activity.clone()).await.map_err(|e| {
            log::error!("Failed to create Activity: {e}");
            StatusCode::INTERNAL_SERVER_ERROR
        })?;

        match target_activity.kind {
            ActivityType::Like => {
                revoke_activity_by_apid(conn, target_ap_id.clone())
                    .await
                    .map_err(|e| {
                        log::error!("Failed to revoke Like: {e}");
                        StatusCode::INTERNAL_SERVER_ERROR
                    })?;
                Ok(StatusCode::ACCEPTED)
            }
            ActivityType::Follow => {
                let followed_actor_ap_id = target_activity.target_ap_id.ok_or_else(|| {
                    log::error!("Failed to identify followed Actor");
                    StatusCode::INTERNAL_SERVER_ERROR
                })?;

                let follow_activity_ap_id = target_activity.ap_id.clone().ok_or_else(|| {
                    log::error!("Failed to identify Follow Activity");
                    StatusCode::INTERNAL_SERVER_ERROR
                })?;

                if delete_follow(
                    conn,
                    target_activity.actor.to_string(),
                    followed_actor_ap_id,
                )
                .await
                .is_ok()
                    && revoke_activity_by_apid(conn, follow_activity_ap_id)
                        .await
                        .is_ok()
                {
                    log::info!("Follower record deleted: {target_ap_id}");
                }

                Ok(StatusCode::ACCEPTED)
            }
            ActivityType::Announce => {
                let pool = pool.clone();
                let ap_id = target_ap_id.clone();

                tokio::spawn(async move {
                    if let Err(e) =
                        runner::announce::remote_undo_announce_task(pool, None, vec![ap_id]).await
                    {
                        log::error!("Failed to run remote_undo_announce_task: {e:?}");
                    }
                });
                Ok(StatusCode::ACCEPTED)
            }
            _ => Err(StatusCode::NOT_IMPLEMENTED),
        }
    }

    fn actor(&self) -> ApAddress {
        self.actor.clone()
    }
}