Lemmy 1.0's multi-communities and PieFed's feeds (`type: Feed`) resolve as accounts: the feed's `following` is kept
once a day with its counts, each community in it is read in turn, and `/api/v1/accounts/:id/following` lists them.
Lemmy's feed carries the instance's key and its text in `description`; both are taken as they are. Following a feed
answers 422 until the owner decides how a feed is followed.
A post moved to another community (PieFed's Move{object: post, origin, target}), relayed by the community it leaves,
goes there with its thread; a move into a community we host is not taken.
Checked in the pasture: a Lemmy 1.0 feed and a PieFed feed list their communities (ours among them); a PieFed post moved
from its web code arrives moved, with its comment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
This commit is contained in:
1 parent
62189bf11d
commit
3b3f1f6b93
10 files changed
+226
-25
No files matched your search
@@ -0,0 +1,67 @@
|
||||
using PrivaPub.Federation.Actors;
|
||||
using PrivaPub.Models.Jobs;
|
||||
using PrivaPub.Tests.Support;
|
||||
using PrivaPub.Tests.Support.Host;
|
||||
|
||||
using System.Net;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace PrivaPub.Tests.Http
|
||||
{
|
||||
// Lemmy 1.0's multi-communities and PieFed's feeds are `Feed` actors whose `following` is their communities
|
||||
[Trait("Category", "Integration")]
|
||||
public sealed class MastodonFeedTests : IAsyncLifetime
|
||||
{
|
||||
PrivaPubHost _host;
|
||||
Peer _peer;
|
||||
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
Assert.SkipUnless(MongoFixture.Enabled, MongoFixture.Skip);
|
||||
_host = await PrivaPubHost.Shared();
|
||||
_peer = await Peer.Start();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_peer != default)
|
||||
await _peer.DisposeAsync();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task A_feed_shows_as_an_account_whose_following_is_its_communities()
|
||||
{
|
||||
var token = TestContext.Current.CancellationToken;
|
||||
var reader = await _host.Mastodon("feeder");
|
||||
var cats = new RemoteActor(_peer, "cats", type: "Group");
|
||||
var dogs = new RemoteActor(_peer, "dogs", type: "Group");
|
||||
var name = $"feed{Guid.NewGuid():N}"[..12];
|
||||
var feed = $"{_peer.A}/m/{name}";
|
||||
// as Lemmy serves one: the instance's inbox and key, its text in `description`
|
||||
_peer.Serve($"/m/{name}", new JsonObject
|
||||
{
|
||||
["@context"] = new JsonArray("https://join-lemmy.org/context.json", "https://www.w3.org/ns/activitystreams"),
|
||||
["type"] = "Feed", ["id"] = feed, ["inbox"] = $"{_peer.A}/inbox",
|
||||
["publicKey"] = new JsonObject { ["id"] = $"{_peer.A}/#main-key", ["owner"] = $"{_peer.A}/", ["publicKeyPem"] = "-----BEGIN PUBLIC KEY-----\n-----END PUBLIC KEY-----\n" },
|
||||
["following"] = $"{feed}/following", ["preferredUsername"] = name, ["name"] = "Pets", ["description"] = "every pet",
|
||||
["attributedTo"] = $"{_peer.A}/users/owner"
|
||||
}.ToJsonString());
|
||||
_peer.Serve($"/m/{name}/following", new JsonObject
|
||||
{
|
||||
["type"] = "Collection", ["id"] = $"{feed}/following", ["totalItems"] = 2, ["items"] = new JsonArray(cats.Id, dogs.Id)
|
||||
}.ToJsonString());
|
||||
|
||||
var account = await _host.Get<IRemoteActorService>().GetActor(feed, refresh: true, token);
|
||||
Assert.NotNull(account);
|
||||
await _host.Run(j => j.Kind == JobKind.CountAccount && j.Payload == feed, token);
|
||||
|
||||
var shown = (await reader.Client.Get($"/api/v1/accounts/{account.ID}")).Ok().Body;
|
||||
Assert.Equal(("Pets", 2), (shown.Text("display_name"), shown.Number("following_count")));
|
||||
Assert.Contains("every pet", shown.Text("note"));
|
||||
var communities = (await reader.Client.Get($"/api/v1/accounts/{account.ID}/following")).Ok().Array;
|
||||
Assert.Equal(new[] { cats.Id, dogs.Id }, communities.Select(c => c.Text("uri")));
|
||||
Assert.All(communities, c => Assert.True(c!["group"]!.GetValue<bool>()));
|
||||
Assert.Equal(HttpStatusCode.UnprocessableEntity, (await reader.Client.Post($"/api/v1/accounts/{account.ID}/follow")).Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user