A remote thread brings the replies that never reached us
The context of a remote post showed only what PrivaPub happened to hold: replies from servers nobody here follows were never seen, and only the ancestors were ever fetched. Now a persona opening a public remote thread queues FetchReplies for the post and its root, at most once an hour each. The job reads the thread's own collection first (FEP-7888 `context`, which Mastodon 4.5+ serves with every reply at any depth; posts or, as FEP-f228 allows, the activities that made them), and otherwise the post's `replies` (PeerTube's `comments`) and the replies' own, two levels down. At most 5 pages and 100 posts a job, signed by the instance actor, never a persona; each post is fetched from its own origin and stored through StoreContext, so only public and unlisted ones are kept. 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
bbeeda7268
commit
0695c08ac3
12 files changed
+344
-5
No files matched your search
@@ -1,5 +1,6 @@
|
||||
using MongoDB.Entities;
|
||||
|
||||
using PrivaPub.Models.Jobs;
|
||||
using PrivaPub.Models.User;
|
||||
using PrivaPub.Tests.Support;
|
||||
using PrivaPub.Tests.Support.Host;
|
||||
@@ -133,6 +134,36 @@ namespace PrivaPub.Tests.Http
|
||||
Assert.Equal(1, (await alice.Client.Get($"/api/v1/statuses/{parent.ID}")).Ok().Body.Number("replies_count"));
|
||||
}
|
||||
|
||||
// a remote thread opened by a persona has its replies read from its server (here its FEP-7888 context), at most hourly
|
||||
[Fact]
|
||||
public async Task Opening_a_remote_thread_reads_the_replies_that_never_reached_us()
|
||||
{
|
||||
var token = TestContext.Current.CancellationToken;
|
||||
var alice = await _host.Mastodon("alice");
|
||||
var bob = new RemoteActor(_peer, "bob");
|
||||
var carol = new RemoteActor(_peer, "carol");
|
||||
var context = $"{bob.Origin()}/contexts/{Guid.NewGuid():N}";
|
||||
var post = await _host.PublicPostFrom(bob, alice, shape: note => note["context"] = context);
|
||||
var answer = carol.Create("<p>said elsewhere</p>", new[] { MastodonHelpers.Public }, new[] { carol.Id + "/followers" },
|
||||
note => note["inReplyTo"] = post.ObjectURI)["object"]!;
|
||||
var answerId = answer["id"]!.GetValue<string>();
|
||||
_peer.Serve(new Uri(answerId).AbsolutePath, answer.ToJsonString());
|
||||
_peer.Serve(new Uri(context).AbsolutePath, new JsonObject
|
||||
{
|
||||
["id"] = context, ["type"] = "OrderedCollection", ["orderedItems"] = new JsonArray(post.ObjectURI, answerId)
|
||||
}.ToJsonString());
|
||||
async Task<int> Queued() => (await DB.Default.Find<Job>().Match(j => j.Kind == JobKind.FetchReplies && j.Payload.Contains(post.ID)).ExecuteAsync(token)).Count;
|
||||
|
||||
(await _host.Client().Get($"/api/v1/statuses/{post.ID}/context")).Ok();
|
||||
Assert.Equal(0, await Queued());
|
||||
Assert.Empty((await alice.Client.Get($"/api/v1/statuses/{post.ID}/context")).Ok().Body["descendants"]!.AsArray());
|
||||
Assert.Equal(1, await _host.Run(j => j.Kind == JobKind.FetchReplies && j.Payload.Contains(post.ID), token));
|
||||
|
||||
var descendants = (await alice.Client.Get($"/api/v1/statuses/{post.ID}/context")).Ok().Body["descendants"]!.AsArray();
|
||||
Assert.Equal(answerId, Assert.Single(descendants).Text("uri"));
|
||||
Assert.Equal(1, await Queued());
|
||||
}
|
||||
|
||||
// Akkoma marks a post with sensitive media "sensitive" and leaves its summary empty: the media is hidden, the words are
|
||||
// not, and no warning is made up for them (found by decePub's e2e tests on the town)
|
||||
[Fact]
|
||||
|
||||
Reference in new issue
Block a user