Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f240828cf | ||
|
|
5ecf2d9629 |
No files matched your search
@@ -217,7 +217,9 @@ group www-data and reaches the private mongod; `sudo -u www-data` works too.
|
|||||||
when a refetch answers 404, which is why this matters.
|
when a refetch answers 404, which is why this matters.
|
||||||
**Communities** are FEP-1b12 groups: `GroupDistributor` announces the whole activity (plus the object for new posts,
|
**Communities** are FEP-1b12 groups: `GroupDistributor` announces the whole activity (plus the object for new posts,
|
||||||
for Mastodon), top-level posts are `Page`s with a `name`, posting follows `Group.PostingPolicy`.
|
for Mastodon), top-level posts are `Page`s with a `name`, posting follows `Group.PostingPolicy`.
|
||||||
Located posts (`LocalGeo`) are the only local-only posts.
|
Located posts (`LocalGeo`) are the only local-only posts. The Mastodon API looks past them everywhere, homes
|
||||||
|
included (the fan-out gives them no `TimelineEntry`, not even their author's): they are read through
|
||||||
|
`/clientapi/post/nearby` and deleted through `/clientapi/post/delete`.
|
||||||
9. **A DM joins a conversation only by `DmGroup.ParticipantsKey`**, the exact set of its participants; a remote
|
9. **A DM joins a conversation only by `DmGroup.ParticipantsKey`**, the exact set of its participants; a remote
|
||||||
`context` decides nothing. DMs are `Post`s with `Visibility = Direct` and a `ConversationId` (`DmPost` is legacy).
|
`context` decides nothing. DMs are `Post`s with `Visibility = Direct` and a `ConversationId` (`DmPost` is legacy).
|
||||||
`DmGroup.LastPostId` pages `/api/v1/conversations`, and `ConversationState` keeps each persona's read and removed
|
`DmGroup.LastPostId` pages `/api/v1/conversations`, and `ConversationState` keeps each persona's read and removed
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ namespace PrivaPub.Tests.Domain
|
|||||||
.Select(j => JsonSerializer.Deserialize<DeliveryPayload>(j.Payload))
|
.Select(j => JsonSerializer.Deserialize<DeliveryPayload>(j.Payload))
|
||||||
.Where(p => p.Body.Contains(post.ID));
|
.Where(p => p.Body.Contains(post.ID));
|
||||||
Assert.Empty(outgoing);
|
Assert.Empty(outgoing);
|
||||||
|
// nor reaches a home, its author's included: the Mastodon API looks past it, so there it could not be acted on
|
||||||
|
Assert.False(await DB.Default.Find<PrivaPub.Models.Social.TimelineEntry>().Match(e => e.PostId == post.ID).ExecuteAnyAsync(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ namespace PrivaPub.Tests.Federation
|
|||||||
{
|
{
|
||||||
static readonly string[] PeerHosts = { "localhost", "127.0.0.1" };
|
static readonly string[] PeerHosts = { "localhost", "127.0.0.1" };
|
||||||
|
|
||||||
|
// (a test sees only the deliveries queued since it began: the others' share the database)
|
||||||
|
readonly DateTime _started = DateTime.UtcNow;
|
||||||
Harness _harness;
|
Harness _harness;
|
||||||
|
|
||||||
public async ValueTask InitializeAsync()
|
public async ValueTask InitializeAsync()
|
||||||
@@ -74,10 +76,9 @@ namespace PrivaPub.Tests.Federation
|
|||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<List<(DeliveryPayload Payload, JsonObject Body)>> Queued() =>
|
async Task<List<DeliveryPayload>> Queued() =>
|
||||||
(await DB.Default.Find<Job>().Match(j => j.Kind == JobKind.Deliver && j.CreatedAt >= DateTime.UtcNow.AddMinutes(-5)).ExecuteAsync(Token))
|
(await DB.Default.Find<Job>().Match(j => j.Kind == JobKind.Deliver && j.CreatedAt >= _started).ExecuteAsync(Token))
|
||||||
.Select(j => JsonSerializer.Deserialize<DeliveryPayload>(j.Payload))
|
.Select(j => JsonSerializer.Deserialize<DeliveryPayload>(j.Payload))
|
||||||
.Select(p => (p, JsonNode.Parse(p.Body)!.AsObject()))
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// a community on a Lemmy, or on a server that takes reports as Lemmy does (the peer as localhost), and one of its posters there
|
// a community on a Lemmy, or on a server that takes reports as Lemmy does (the peer as localhost), and one of its posters there
|
||||||
@@ -118,11 +119,12 @@ namespace PrivaPub.Tests.Federation
|
|||||||
Assert.Equal("a slur in the title", flag["summary"]!.GetValue<string>());
|
Assert.Equal("a slur in the title", flag["summary"]!.GetValue<string>());
|
||||||
Assert.Equal("a slur in the title", flag["content"]!.GetValue<string>());
|
Assert.Equal("a slur in the title", flag["content"]!.GetValue<string>());
|
||||||
Assert.Empty(await _harness.Outgoing(poster.Id + "/inbox"));
|
Assert.Empty(await _harness.Outgoing(poster.Id + "/inbox"));
|
||||||
Assert.DoesNotContain(await Queued(), q => q.Payload.Inbox != community.SharedInbox && q.Body.ToJsonString().Contains(post.ObjectURI));
|
Assert.DoesNotContain(await Queued(), q => q.Inbox != community.SharedInbox && q.Body.Contains(post.ObjectURI));
|
||||||
Assert.DoesNotContain(alice.UserName, flag.ToJsonString());
|
Assert.DoesNotContain(alice.UserName, flag.ToJsonString());
|
||||||
Assert.DoesNotContain(alice.Id, flag.ToJsonString());
|
Assert.DoesNotContain(alice.Id, flag.ToJsonString());
|
||||||
var queued = Assert.Single(await Queued(), q => q.Body["actor"]!.GetValue<string>() == reporter.Uri && q.Body["object"]!.GetValue<string>() == post.ObjectURI);
|
var queued = Assert.Single(await Queued(), q => q.Inbox == community.SharedInbox);
|
||||||
Assert.Equal(LocalActorKind.Reporter, queued.Payload.SignerKind);
|
Assert.Equal(LocalActorKind.Reporter, queued.SignerKind);
|
||||||
|
Assert.Equal(reporter.Id, queued.SignerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ namespace PrivaPub.Api.Mastodon.Controllers
|
|||||||
home.Match(e => !apart.Contains(e.AuthorAccountId));
|
home.Match(e => !apart.Contains(e.AuthorAccountId));
|
||||||
var entries = await Page.From(Params, Limit()).Fetch(home, e => e.PostId, token);
|
var entries = await Page.From(Params, Limit()).Fetch(home, e => e.PostId, token);
|
||||||
var ids = entries.Select(e => e.PostId).ToList();
|
var ids = entries.Select(e => e.PostId).ToList();
|
||||||
var posts = (await _dbEntities.Posts.Match(p => ids.Contains(p.ID)).Match(VisibilityPolicy.IsShown).ExecuteAsync(token)).ToDictionary(p => p.ID);
|
// (located posts once reached their author's home: the entries left from then are passed over)
|
||||||
|
var posts = (await _dbEntities.Posts.Match(p => ids.Contains(p.ID) && p.Visibility != PostVisibility.LocalGeo).Match(VisibilityPolicy.IsShown)
|
||||||
|
.ExecuteAsync(token)).ToDictionary(p => p.ID);
|
||||||
var statuses = await _mapper.Statuses(ids.Where(posts.ContainsKey).Select(id => posts[id]).ToList(), MyId, token);
|
var statuses = await _mapper.Statuses(ids.Where(posts.ContainsKey).Select(id => posts[id]).ToList(), MyId, token);
|
||||||
Link("/api/v1/timelines/home", entries.LastOrDefault()?.PostId, entries.FirstOrDefault()?.PostId);
|
Link("/api/v1/timelines/home", entries.LastOrDefault()?.PostId, entries.FirstOrDefault()?.PostId);
|
||||||
return Json(statuses);
|
return Json(statuses);
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ namespace PrivaPub.Domain.Timelines
|
|||||||
|
|
||||||
public async Task Distribute(Post post, CancellationToken token)
|
public async Task Distribute(Post post, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
// a located post is read only through /clientapi/post/nearby: the Mastodon API looks past it everywhere, so in a
|
||||||
|
// home, its author's included, it would be a status nothing can be done to (and it would read as public)
|
||||||
|
if (post.Visibility == PostVisibility.LocalGeo)
|
||||||
|
return;
|
||||||
|
|
||||||
var recipients = new HashSet<string>(StringComparer.Ordinal);
|
var recipients = new HashSet<string>(StringComparer.Ordinal);
|
||||||
if (!post.IsFederatedCopy && !string.IsNullOrEmpty(post.GroupUserId))
|
if (!post.IsFederatedCopy && !string.IsNullOrEmpty(post.GroupUserId))
|
||||||
recipients.Add(post.GroupUserId);
|
recipients.Add(post.GroupUserId);
|
||||||
|
|||||||
Reference in new issue
Block a user