feat(activitypub): ThoughtNote AP object and ThoughtsObjectHandler

This commit is contained in:
2026-05-14 10:23:35 +02:00
parent 21b6a04f97
commit 2080fec347
5 changed files with 270 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
use activitypub_base::AS_PUBLIC;
use activitypub_federation::kinds::object::NoteType;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use url::Url;
/// AP Note representing a Thought.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThoughtNote {
#[serde(rename = "type")]
pub kind: NoteType,
pub id: Url,
pub attributed_to: Url,
pub content: String,
pub published: DateTime<Utc>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub to: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub cc: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub in_reply_to: Option<Url>,
pub sensitive: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
}
impl ThoughtNote {
pub fn new_public(
id: Url, actor_url: Url, content: String, published: DateTime<Utc>,
in_reply_to: Option<Url>, sensitive: bool, summary: Option<String>,
followers_url: Url,
) -> Self {
Self {
kind: Default::default(),
id, attributed_to: actor_url, content, published,
to: vec![AS_PUBLIC.to_string()],
cc: vec![followers_url.to_string()],
in_reply_to, sensitive, summary,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn note_serializes_with_public_audience() {
let note = ThoughtNote::new_public(
"https://example.com/thoughts/1".parse().unwrap(),
"https://example.com/users/alice".parse().unwrap(),
"Hello world".to_string(),
chrono::Utc::now(),
None, false, None,
"https://example.com/users/alice/followers".parse().unwrap(),
);
let json = serde_json::to_string(&note).unwrap();
assert!(json.contains(AS_PUBLIC));
assert!(json.contains("Hello world"));
}
}