enigmatick 0.4.1

Enigmatick is a social media platform that integrates with servers that implement the ActivityPub protocol (e.g., Mastodon)
Documentation
use crate::db::runner::DbRunner;
use crate::models::actors::Actor;
use axum::response::Redirect;
use axum::{
    http::{header, StatusCode},
    response::{IntoResponse, Json, Response},
};
use deadpool_diesel::postgres::Pool;
use enum_dispatch::enum_dispatch;
use jdt_activity_pub::{ApActivity, ApAddress, ApObject};
use serde::Serialize;
use serde_json::Value;

pub mod admin;
pub mod authentication;
pub mod client;
pub mod encryption;
pub mod image;
pub mod inbox;
pub mod instance;
pub mod objects;
pub mod outbox;
pub mod remote;
pub mod user;
pub mod vault;
pub mod webfinger;

pub enum AbstractResponse<T> {
    ActivityJson(ActivityJson<T>),
    LdJson(LdJson<T>),
    JrdJson(JrdJson<T>),
    XrdXml(XrdXml),
    Redirect(Redirect),
    Json(Json<T>),
}

pub struct ActivityJson<T>(pub T);

impl<T: Serialize> IntoResponse for ActivityJson<T> {
    fn into_response(self) -> Response {
        let mut res = axum::response::Json(self.0).into_response();
        res.headers_mut().insert(
            header::CONTENT_TYPE,
            "application/activity+json".parse().unwrap(),
        );
        res
    }
}

pub struct LdJson<T>(pub T);

impl<T: Serialize> IntoResponse for LdJson<T> {
    fn into_response(self) -> Response {
        let mut res = axum::response::Json(self.0).into_response();
        res.headers_mut().insert(
            header::CONTENT_TYPE,
            "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
                .parse()
                .unwrap(),
        );
        res
    }
}

pub struct JrdJson<T>(pub T);

impl<T: Serialize> IntoResponse for JrdJson<T> {
    fn into_response(self) -> Response {
        let mut res = axum::response::Json(self.0).into_response();
        res.headers_mut().insert(
            header::CONTENT_TYPE,
            "application/jrd+json".parse().unwrap(),
        );
        res
    }
}

pub struct XrdXml(String);

impl IntoResponse for XrdXml {
    fn into_response(self) -> Response {
        let mut res = self.0.into_response();
        res.headers_mut()
            .insert(header::CONTENT_TYPE, "application/xrd+xml".parse().unwrap());
        res
    }
}

impl<T: Serialize> IntoResponse for AbstractResponse<T> {
    fn into_response(self) -> Response {
        match self {
            AbstractResponse::ActivityJson(json) => json.into_response(),
            AbstractResponse::LdJson(json) => json.into_response(),
            AbstractResponse::JrdJson(json) => json.into_response(),
            AbstractResponse::XrdXml(xml) => xml.into_response(),
            AbstractResponse::Redirect(redirect) => redirect.into_response(),
            AbstractResponse::Json(json) => json.into_response(),
        }
    }
}

#[enum_dispatch(ApActivity)]
pub trait Inbox {
    async fn inbox<C: DbRunner>(
        &self,
        _conn: &C,
        _pool: Pool,
        _raw: Value,
    ) -> Result<StatusCode, StatusCode> {
        Err(StatusCode::NOT_IMPLEMENTED)
    }

    #[allow(dead_code)]
    fn actor(&self) -> ApAddress {
        ApAddress::None
    }
}

impl Inbox for ApActivity {
    async fn inbox<C: DbRunner>(
        &self,
        conn: &C,
        pool: Pool,
        raw: Value,
    ) -> Result<StatusCode, StatusCode> {
        match self {
            ApActivity::Delete(delete) => (*delete).inbox(conn, pool, raw).await,
            ApActivity::Like(like) => (*like).inbox(conn, pool, raw).await,
            ApActivity::Undo(undo) => (*undo).inbox(conn, pool, raw).await,
            ApActivity::Accept(accept) => (*accept).inbox(conn, pool, raw).await,
            ApActivity::Follow(follow) => follow.inbox(conn, pool, raw).await,
            ApActivity::Announce(announce) => announce.inbox(conn, pool, raw).await,
            ApActivity::Create(create) => create.inbox(conn, pool, raw).await,
            ApActivity::Update(update) => update.inbox(conn, pool, raw).await,
            ApActivity::Block(block) => block.inbox(conn, pool, raw).await,
            ApActivity::Add(add) => add.inbox(conn, pool, raw).await,
            ApActivity::Remove(remove) => remove.inbox(conn, pool, raw).await,
            ApActivity::Move(move_activity) => move_activity.inbox(conn, pool, raw).await,
        }
    }

    fn actor(&self) -> ApAddress {
        match self {
            ApActivity::Delete(delete) => delete.actor.clone(),
            ApActivity::Like(like) => like.actor.clone(),
            ApActivity::Undo(undo) => undo.actor.clone(),
            ApActivity::Accept(accept) => accept.actor.clone(),
            ApActivity::Follow(follow) => follow.actor.clone(),
            ApActivity::Announce(announce) => announce.actor.clone(),
            ApActivity::Create(create) => create.actor.clone(),
            ApActivity::Update(update) => update.actor.clone(),
            ApActivity::Block(block) => block.actor.clone(),
            ApActivity::Add(add) => add.actor.clone(),
            ApActivity::Remove(remove) => remove.actor.clone(),
            ApActivity::Move(move_activity) => move_activity.actor.clone(),
        }
    }
}

#[enum_dispatch(ApActivity, ApObject)]
pub trait Outbox {
    async fn outbox<C: DbRunner>(
        &self,
        _conn: &C,
        _pool: Pool,
        _profile: Actor,
        _raw: Value,
    ) -> Result<ActivityJson<ApActivity>, StatusCode> {
        Err(StatusCode::NOT_IMPLEMENTED)
    }
}

impl Outbox for ApActivity {
    async fn outbox<C: DbRunner>(
        &self,
        conn: &C,
        pool: Pool,
        profile: Actor,
        raw: Value,
    ) -> Result<ActivityJson<ApActivity>, StatusCode> {
        match self {
            ApActivity::Delete(delete) => (*delete).outbox(conn, pool, profile, raw).await,
            ApActivity::Like(like) => (*like).outbox(conn, pool, profile, raw).await,
            ApActivity::Undo(undo) => (*undo).outbox(conn, pool, profile, raw).await,
            ApActivity::Accept(accept) => (*accept).outbox(conn, pool, profile, raw).await,
            ApActivity::Follow(follow) => follow.outbox(conn, pool, profile, raw).await,
            ApActivity::Announce(announce) => announce.outbox(conn, pool, profile, raw).await,
            ApActivity::Create(create) => create.outbox(conn, pool, profile, raw).await,
            ApActivity::Update(update) => update.outbox(conn, pool, profile, raw).await,
            ApActivity::Block(block) => block.outbox(conn, pool, profile, raw).await,
            ApActivity::Add(add) => add.outbox(conn, pool, profile, raw).await,
            ApActivity::Remove(remove) => remove.outbox(conn, pool, profile, raw).await,
            ApActivity::Move(move_activity) => move_activity.outbox(conn, pool, profile, raw).await,
        }
    }
}

impl Outbox for ApObject {
    async fn outbox<C: DbRunner>(
        &self,
        conn: &C,
        pool: Pool,
        profile: Actor,
        raw: Value,
    ) -> Result<ActivityJson<ApActivity>, StatusCode> {
        match self {
            ApObject::Tombstone(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Session(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Instrument(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Note(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Article(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Question(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Actor(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Collection(x) => x.outbox(conn, pool, profile, raw).await,
            ApObject::Identifier(x) => x.outbox(conn, pool, profile, raw).await,
        }
    }
}