using MongoDB.Entities; using PrivaPub.Models.Post; using PrivaPub.Tests.Support; using PrivaPub.Tests.Support.Host; using System.Text.Json.Nodes; namespace PrivaPub.Tests.Http { // A Pixelfed post's own place: stored from `location`, shown as `privapub.place`, changed by an edit. [Trait("Category", "Integration")] public sealed class PostPlaceTests : 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(); } static CancellationToken Token => TestContext.Current.CancellationToken; static JsonObject Location(string name, string latitude, string longitude) => new() { ["type"] = "Place", ["name"] = name, ["latitude"] = latitude, ["longitude"] = longitude, ["country"] = "Italy" }; [Fact] public async Task A_pixelfed_place_is_shown_and_follows_the_authors_edits() { var alice = await _host.Mastodon("alice"); var ann = new RemoteActor(_peer, "ann"); var post = await _host.PublicPostFrom(ann, alice, "

the duomo

", note => note["location"] = Location("Milan", "45.4642", "9.19")); var place = (await alice.Client.Get($"/api/v1/statuses/{post.ID}")).Ok().Body["privapub"]!["place"]; Assert.Equal(("Milan", "Italy"), (place.Text("name"), place.Text("country"))); Assert.Equal(45.4642, place["latitude"]!.GetValue()); Assert.Equal(9.19, place["longitude"]!.GetValue()); await Edit(ann, alice, post, note => note["location"] = Location("Turin", "45.0703", "7.6869")); Assert.Equal("Turin", (await alice.Client.Get($"/api/v1/statuses/{post.ID}")).Ok().Body["privapub"]!["place"].Text("name")); await Edit(ann, alice, post, _ => { }); Assert.Null((await alice.Client.Get($"/api/v1/statuses/{post.ID}")).Ok().Body["privapub"]!["place"]); Assert.Null((await DB.Default.Find().MatchID(post.ID).ExecuteFirstAsync(Token)).Place); } [Fact] public async Task A_post_without_a_place_has_none() { var alice = await _host.Mastodon("alice"); var post = await _host.PublicPostFrom(new RemoteActor(_peer, "plain"), alice); Assert.Null((await alice.Client.Get($"/api/v1/statuses/{post.ID}")).Ok().Body["privapub"]!["place"]); } [Fact] public async Task A_local_post_never_carries_a_location() { var alice = await _host.Mastodon("alice"); var status = await alice.Status("made here"); using var client = _host.Client(); client.DefaultRequestHeaders.Accept.ParseAdd("application/activity+json"); var note = JsonNode.Parse(await client.GetStringAsync(status.Text("uri"), Token))!; Assert.Null(note["location"]); } async Task Edit(RemoteActor author, Mastodon mentioned, Post post, Action shape) { var note = new JsonObject { ["id"] = post.ObjectURI, ["type"] = "Note", ["attributedTo"] = author.Id, ["to"] = new JsonArray(MastodonHelpers.Public), ["cc"] = new JsonArray(mentioned.Uri), ["content"] = "

the duomo, again

", ["published"] = post.CreationDate.ToString("O"), ["updated"] = DateTime.UtcNow.ToString("O"), ["tag"] = new JsonArray(new JsonObject { ["type"] = "Mention", ["href"] = mentioned.Uri, ["name"] = "@" + mentioned.UserName }) }; shape(note); await _host.Deliver(author, mentioned.Mouth, new JsonObject { ["id"] = $"{post.ObjectURI}/updates/{Guid.NewGuid():N}", ["type"] = "Update", ["actor"] = author.Id, ["to"] = new JsonArray(MastodonHelpers.Public), ["object"] = note }); } } }