feat: v2 rewrite — hexagonal arch, ActivityPub federation, NATS, deployment-ready #1
@@ -1394,11 +1394,15 @@ impl domain::ports::FederationActionPort for ActivityPubService {
|
||||
public_key: actor.public_key_pem.clone(),
|
||||
avatar_url: actor.avatar_url.as_ref().map(|u| u.to_string()),
|
||||
last_fetched_at: actor.last_refreshed_at,
|
||||
bio: None,
|
||||
banner_url: None,
|
||||
also_known_as: None,
|
||||
outbox_url: None,
|
||||
attachment: vec![],
|
||||
bio: actor.bio.clone(),
|
||||
banner_url: actor.banner_url.as_ref().map(|u| u.to_string()),
|
||||
also_known_as: actor.also_known_as.clone(),
|
||||
outbox_url: Some(actor.outbox_url.to_string()),
|
||||
attachment: actor
|
||||
.attachment
|
||||
.iter()
|
||||
.map(|f| (f.name.clone(), f.value.clone()))
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1519,12 +1523,61 @@ impl domain::ports::FederationActionPort for ActivityPubService {
|
||||
|
||||
async fn fetch_outbox_page(
|
||||
&self,
|
||||
_outbox_url: &str,
|
||||
_page: u32,
|
||||
outbox_url: &str,
|
||||
page: u32,
|
||||
) -> Result<Vec<domain::models::remote_note::RemoteNote>, domain::errors::DomainError> {
|
||||
Err(domain::errors::DomainError::Internal(
|
||||
"not implemented".into(),
|
||||
))
|
||||
use chrono::DateTime;
|
||||
|
||||
let url = format!("{}?page={}", outbox_url, page);
|
||||
let resp: serde_json::Value = reqwest::Client::new()
|
||||
.get(&url)
|
||||
.header("Accept", "application/activity+json, application/ld+json")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
|
||||
|
||||
let empty = vec![];
|
||||
let items = resp["orderedItems"].as_array().unwrap_or(&empty);
|
||||
|
||||
let notes = items
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
// Items are Create activities wrapping a Note, or Notes directly
|
||||
let note = if item["type"].as_str() == Some("Create") {
|
||||
&item["object"]
|
||||
} else if item["type"].as_str() == Some("Note") {
|
||||
item
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// Only public notes
|
||||
let to = note["to"].as_array()?;
|
||||
let is_public = to
|
||||
.iter()
|
||||
.any(|t| t.as_str() == Some("https://www.w3.org/ns/activitystreams#Public"));
|
||||
if !is_public {
|
||||
return None;
|
||||
}
|
||||
|
||||
let published = DateTime::parse_from_rfc3339(note["published"].as_str()?)
|
||||
.ok()?
|
||||
.with_timezone(&chrono::Utc);
|
||||
|
||||
Some(domain::models::remote_note::RemoteNote {
|
||||
ap_id: note["id"].as_str()?.to_string(),
|
||||
content: note["content"].as_str().unwrap_or("").to_string(),
|
||||
published,
|
||||
sensitive: note["sensitive"].as_bool().unwrap_or(false),
|
||||
content_warning: note["summary"].as_str().map(|s| s.to_string()),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(notes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user