Pins across servers, both ways
An account elsewhere that pins or unpins one of its posts (Add or Remove on its `featured`) now shows those pins on its profile here (`pinned=true`), in its order and its public posts only; a community's announce of a moderator's Add does the same for the community. The `featured` collection itself is read with the account's counts, at most once a day, so pins made before PrivaPub ever saw an account show too. Any other target (Smithereen's wall, a community's moderators) is dropped. A persona's pin and unpin go to the post's audience as Add and Remove on /trophies, as Mastodon sends them. Checked live against Mastodon (scenarios/pins.sh, 8 checks). The town's checker learnt three peer rules from the village: Misskey and Sharkey keep a forwarded reply only with its author's LD signature (only Mastodon signs), they count no renote by a bot, and Mastodon never sees a Lemmy vote on a post in a community. The village of 2026-10-05 checks clean, 2454 of 2454. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
5f150b7a59
commit
1c7d1ece9c
23 files changed
+510
-19
No files matched your search
@@ -20,6 +20,7 @@ namespace PrivaPub.Federation.Outbox
|
||||
Task Publish(LocalActor author, PostEntity post, JsonObject activity, CancellationToken token);
|
||||
Task PublishUpdate(LocalActor author, PostEntity post, string reason, CancellationToken token);
|
||||
Task PublishProfile(LocalActor actor, CancellationToken token);
|
||||
Task PublishFeatured(string personaId, PostEntity post, bool featured, CancellationToken token);
|
||||
}
|
||||
|
||||
public class OutboxPublisher : IOutboxPublisher
|
||||
@@ -110,6 +111,26 @@ namespace PrivaPub.Federation.Outbox
|
||||
await _delivery.Enqueue(author, inboxes, activity, token);
|
||||
}
|
||||
|
||||
// a persona pins its post or unpins it: Add or Remove on its featured collection (/trophies, which serves the same
|
||||
// pins), told to the post's audience as Mastodon tells it
|
||||
public async Task PublishFeatured(string personaId, PostEntity post, bool featured, CancellationToken token)
|
||||
{
|
||||
var author = await _localActors.FindById(LocalActorKind.Person, personaId, token);
|
||||
if (author is not { IsFederated: true } || post.IsLocalOnly)
|
||||
return;
|
||||
await Publish(author, post, new JsonObject
|
||||
{
|
||||
["@context"] = ActivityPubRenderer.Context(),
|
||||
["id"] = author.ActivityUri($"{(featured ? "feature" : "unfeature")}-{post.ID}-{DateTime.UtcNow.Ticks}"),
|
||||
["type"] = featured ? "Add" : "Remove",
|
||||
["actor"] = author.Uri,
|
||||
["object"] = author.PostUri(post.ID),
|
||||
["target"] = author.Featured,
|
||||
["to"] = new JsonArray(Objects.Addressing.Public),
|
||||
["cc"] = new JsonArray(author.Followers)
|
||||
}, token);
|
||||
}
|
||||
|
||||
public async Task PublishUpdate(LocalActor author, PostEntity post, string reason, CancellationToken token)
|
||||
{
|
||||
var group = string.IsNullOrEmpty(post.GroupId) ? default : await _localActors.FindById(LocalActorKind.Group, post.GroupId, token);
|
||||
|
||||
Reference in new issue
Block a user