Some checks failed
CI / Check / Test (push) Has been cancelled
- Broadcast GoalUpdated AP note after ReviewLogged so federated goal progress reflects the new review count without requiring a manual goal edit - Add attribution check in GoalObjectHandler::on_update (mirrors review_handler) to prevent any remote actor from overwriting another's goal - Implement on_actor_removed in GoalObjectHandler via new RemoteGoalRepository::remove_all_by_actor — remote goals were never cleaned up when an actor unfollowed or was deleted - Add remove_all_by_actor to SQLite, Postgres, Noop, and test Panic impls
96 lines
2.9 KiB
Rust
96 lines
2.9 KiB
Rust
use std::sync::Arc;
|
|
|
|
use async_trait::async_trait;
|
|
use domain::{models::RemoteGoalEntry, ports::RemoteGoalRepository};
|
|
use k_ap::ApObjectHandler;
|
|
use url::Url;
|
|
|
|
use crate::objects::GoalObject;
|
|
|
|
pub struct GoalObjectHandler {
|
|
pub remote_goal_repo: Arc<dyn RemoteGoalRepository>,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl ApObjectHandler for GoalObjectHandler {
|
|
async fn on_create(
|
|
&self,
|
|
ap_id: &Url,
|
|
actor_url: &Url,
|
|
object: serde_json::Value,
|
|
) -> anyhow::Result<()> {
|
|
let obj: GoalObject = match serde_json::from_value(object) {
|
|
Ok(o) => o,
|
|
Err(e) => {
|
|
tracing::warn!(ap_id = %ap_id, "ignoring malformed goal Create: {}", e);
|
|
return Ok(());
|
|
}
|
|
};
|
|
let entry = RemoteGoalEntry {
|
|
ap_id: ap_id.as_str().to_string(),
|
|
actor_url: actor_url.as_str().to_string(),
|
|
year: obj.goal_year,
|
|
target_count: obj.goal_target,
|
|
current_count: obj.goal_current,
|
|
received_at: chrono::Utc::now(),
|
|
};
|
|
self.remote_goal_repo.save(entry).await?;
|
|
tracing::info!(ap_id = %ap_id, year = obj.goal_year, "saved remote goal");
|
|
Ok(())
|
|
}
|
|
|
|
async fn on_update(
|
|
&self,
|
|
ap_id: &Url,
|
|
actor_url: &Url,
|
|
object: serde_json::Value,
|
|
) -> anyhow::Result<()> {
|
|
let obj: GoalObject = match serde_json::from_value(object) {
|
|
Ok(o) => o,
|
|
Err(e) => {
|
|
tracing::warn!(ap_id = %ap_id, "ignoring malformed goal Update: {}", e);
|
|
return Ok(());
|
|
}
|
|
};
|
|
if obj.attributed_to != *actor_url {
|
|
anyhow::bail!("goal Update actor does not match object attributed_to");
|
|
}
|
|
self.remote_goal_repo
|
|
.update_by_ap_id(ap_id.as_str(), obj.goal_target, obj.goal_current)
|
|
.await?;
|
|
tracing::info!(ap_id = %ap_id, "updated remote goal progress");
|
|
Ok(())
|
|
}
|
|
|
|
async fn on_delete(&self, ap_id: &Url, actor_url: &Url) -> anyhow::Result<()> {
|
|
self.remote_goal_repo
|
|
.remove_by_ap_id(ap_id.as_str(), actor_url.as_str())
|
|
.await?;
|
|
tracing::info!(ap_id = %ap_id, "removed remote goal");
|
|
Ok(())
|
|
}
|
|
|
|
async fn on_actor_removed(&self, actor_url: &Url) -> anyhow::Result<()> {
|
|
self.remote_goal_repo
|
|
.remove_all_by_actor(actor_url.as_str())
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn on_like(&self, _: &Url, _: &Url) -> anyhow::Result<()> {
|
|
Ok(())
|
|
}
|
|
async fn on_announce_received(&self, _: &Url, _: &Url) -> anyhow::Result<()> {
|
|
Ok(())
|
|
}
|
|
async fn on_announce_of_remote(&self, _: &Url, _: &Url) -> anyhow::Result<()> {
|
|
Ok(())
|
|
}
|
|
async fn on_unlike(&self, _: &Url, _: &Url) -> anyhow::Result<()> {
|
|
Ok(())
|
|
}
|
|
async fn on_mention(&self, _: &Url, _: uuid::Uuid, _: &Url) -> anyhow::Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|