use crate::server::routes::Outbox;
use crate::{
db::runner::DbRunner,
models::activities::get_unrevoked_activity_by_kind_actor_id_and_target_ap_id,
};
use deadpool_diesel::postgres::Pool;
use jdt_activity_pub::{ApActivity, ApFollow};
use reqwest::StatusCode;
use crate::{
models::{
activities::{create_activity, ActivityType, NewActivity, TryFromExtendedActivity},
actors::{get_actor_by_as_id, Actor},
follows::{create_follow, NewFollow},
},
runner::{self},
};
use serde_json::Value;
use super::ActivityJson;
impl Outbox for ApFollow {
async fn outbox<C: DbRunner>(
&self,
conn: &C,
pool: Pool,
profile: Actor,
raw: Value,
) -> Result<ActivityJson<ApActivity>, StatusCode> {
follow_outbox(conn, pool, self.clone(), profile, raw).await
}
}
async fn follow_outbox<C: DbRunner>(
conn: &C,
pool: Pool,
follow: ApFollow,
profile: Actor,
raw: Value,
) -> Result<ActivityJson<ApActivity>, StatusCode> {
log::debug!("{follow:?}");
let as_id = follow.object.reference().ok_or_else(|| {
log::error!("Follow object is not a reference or does not contain an ID");
StatusCode::BAD_REQUEST
})?;
log::debug!("Follow Object: {as_id}");
let actor_to_follow = get_actor_by_as_id(conn, as_id.clone()).await.map_err(|e| {
log::error!("Failed to retrieve actor to follow '{as_id}': {e:#?}");
StatusCode::NOT_FOUND
})?;
log::debug!("Follow Actor: {actor_to_follow}");
let activity = if let Ok(Some(activity)) =
get_unrevoked_activity_by_kind_actor_id_and_target_ap_id(
conn,
ActivityType::Follow,
profile.id,
as_id.clone(),
)
.await
{
activity
} else {
let mut new_activity =
NewActivity::try_from((follow.clone().into(), Some(actor_to_follow.clone().into())))
.map_err(|e| {
log::error!("Failed to build NewActivity for Follow: {e:#?}");
StatusCode::INTERNAL_SERVER_ERROR
})?
.link_actor(conn)
.await;
new_activity.raw = Some(raw);
let created_activity = create_activity(conn, new_activity.clone())
.await
.map_err(|e| {
log::error!("Failed to create Follow activity in DB: {e:#?}");
StatusCode::INTERNAL_SERVER_ERROR
})?;
let mut new_follow = NewFollow::try_from(follow).map_err(|e| {
log::error!("Failed to build NewFollow from ApFollow: {e:#?}");
StatusCode::INTERNAL_SERVER_ERROR
})?;
new_follow.follow_activity_ap_id = created_activity.ap_id.clone();
new_follow.follower_actor_id = Some(profile.id);
new_follow.leader_actor_id = Some(actor_to_follow.id);
create_follow(conn, new_follow).await.map_err(|e| {
log::error!("Failed to create Follow record in DB: {e:#?}");
StatusCode::INTERNAL_SERVER_ERROR
})?;
created_activity
};
let ap_id = activity.ap_id.clone().ok_or_else(|| {
log::error!("ActivityPub ID cannot be None for federation");
StatusCode::BAD_REQUEST
})?;
runner::run(runner::send_activity_task, pool, None, vec![ap_id]).await;
let ap_activity =
ApActivity::try_from_extended_activity((activity, None, None, Some(actor_to_follow)))
.map_err(|e| {
log::error!("Failed to build ApActivity from ExtendedActivity: {e:#?}");
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(ActivityJson(ap_activity))
}