Files
k-ap/src/featured_handler.rs
Gabriel Kaszewski 48fded426f fix: AP protocol correctness gaps
Undo(Announce): now removes announce record from ActorRepository and
  calls ApObjectHandler::on_announce_removed (default no-op, override
  to decrement boost counts). Announce counts no longer drift.

Undo(Block): now logged at info level instead of silently ignored.
  No automatic relationship restoration (spec doesn't require it).

AddActivity: now uses object["id"] as the stable ap_id (same as
  CreateActivity), falling back to activity id only if object has no
  id field. Fixes keying watchlist/collection items by the wrong id.

Featured collection: GET /users/{id}/featured now served by the router.
  ApContentReader::get_featured_objects() has a default empty-list impl
  — override to expose pinned posts without any breaking changes.
2026-05-29 02:29:38 +02:00

43 lines
1.5 KiB
Rust

use activitypub_federation::{axum::json::FederationJson, config::Data};
use axum::extract::Path;
use serde_json::json;
use crate::data::FederationData;
use crate::error::Error;
use crate::urls::AP_CONTEXT;
/// Serves the `featured` (pinned posts) `OrderedCollection` for a local user.
///
/// Remote servers follow the `featured` link from the actor JSON and expect
/// an `OrderedCollection` whose `orderedItems` are the AP URLs of pinned objects.
/// The handler calls [`ApContentReader::get_featured_objects`] — override that
/// method to expose your pinned posts.
pub async fn featured_handler(
Path(user_id_str): Path<String>,
data: Data<FederationData>,
) -> Result<FederationJson<serde_json::Value>, Error> {
let user_id = uuid::Uuid::parse_str(&user_id_str)
.map_err(|_| Error::not_found(anyhow::anyhow!("user not found")))?;
data.user_repo
.find_by_id(user_id)
.await
.map_err(Error::from)?
.ok_or_else(|| Error::not_found(anyhow::anyhow!("user not found")))?;
let featured_url = format!("{}/users/{}/featured", data.base_url, user_id_str);
let items = data
.content_reader
.get_featured_objects(user_id)
.await
.map_err(|e| Error::from(anyhow::anyhow!("{}", e)))?;
Ok(FederationJson(json!({
"@context": AP_CONTEXT,
"type": "OrderedCollection",
"id": featured_url,
"totalItems": items.len(),
"orderedItems": items.iter().map(|u| u.as_str()).collect::<Vec<_>>(),
})))
}