From 2523f8a4d1734026e7d778ccebf477972e019305 Mon Sep 17 00:00:00 2001 From: Kopper Date: Mon, 9 Sep 2024 17:41:15 +0300 Subject: [PATCH] [backend/federation] Expose replies collection Exposes the replies collection for local notes, allowing remote instances to backfill replies when fetching our posts. --- .../Federation/ActivityPubController.cs | 28 +++++++++++++++++++ .../Federation/ActivityPub/NoteRenderer.cs | 7 +++-- .../ActivityStreams/Types/ASNote.cs | 4 +++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Iceshrimp.Backend/Controllers/Federation/ActivityPubController.cs b/Iceshrimp.Backend/Controllers/Federation/ActivityPubController.cs index 298015c5..74f04989 100644 --- a/Iceshrimp.Backend/Controllers/Federation/ActivityPubController.cs +++ b/Iceshrimp.Backend/Controllers/Federation/ActivityPubController.cs @@ -74,6 +74,34 @@ public class ActivityPubController( .Compact(); } + [HttpGet("/notes/{id}/replies")] + [AuthorizedFetch] + [OverrideResultType] + [ProducesResults(HttpStatusCode.OK)] + [ProducesErrors(HttpStatusCode.NotFound)] + public async Task GetNoteReplies(string id) + { + var actor = HttpContext.GetActor(); + var note = await db.Notes + .EnsureVisibleFor(actor) + .FirstOrDefaultAsync(p => p.Id == id) ?? + throw GracefulException.NotFound("Note not found"); + + var replies = await db.Notes.Where(p => p.ReplyId == id) + .OrderByDescending(p => p.Id) + .ToListAsync(); + + var rendered = replies.Select(noteRenderer.RenderLite).ToList(); + var res = new ASOrderedCollection + { + Id = $"{note.GetPublicUri(config.Value)}/replies", + TotalItems = (ulong)rendered.Count, + Items = rendered.Cast().ToList() + }; + + return res.Compact(); + } + [HttpGet("/users/{id}")] [AuthorizedFetch] [MediaTypeRouteFilter("application/activity+json", "application/ld+json")] diff --git a/Iceshrimp.Backend/Core/Federation/ActivityPub/NoteRenderer.cs b/Iceshrimp.Backend/Core/Federation/ActivityPub/NoteRenderer.cs index 402aa3fe..82b19f19 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityPub/NoteRenderer.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityPub/NoteRenderer.cs @@ -27,8 +27,9 @@ public class NoteRenderer(IOptions config, MfmConverter if (note.IsPureRenote) throw GracefulException.BadRequest("Refusing to render pure renote as ASNote"); - var id = note.GetPublicUri(config.Value); - var userId = note.User.GetPublicUri(config.Value); + var id = note.GetPublicUri(config.Value); + var userId = note.User.GetPublicUri(config.Value); + var replies = new ASOrderedCollection($"{id}/replies"); var replyId = note.Reply != null ? new ASObjectBase(note.Reply.Uri ?? note.Reply.GetPublicUri(config.Value)) : null; @@ -160,6 +161,7 @@ public class NoteRenderer(IOptions config, MfmConverter UpdatedAt = note.UpdatedAt, Sensitive = sensitive, InReplyTo = replyId, + Replies = replies, Cc = cc, To = to, Tags = tags, @@ -190,6 +192,7 @@ public class NoteRenderer(IOptions config, MfmConverter UpdatedAt = note.UpdatedAt, Sensitive = sensitive, InReplyTo = replyId, + Replies = replies, Cc = cc, To = to, Tags = tags, diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs index cfa33bae..1a07de69 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASNote.cs @@ -87,6 +87,10 @@ public class ASNote : ASObject [JC(typeof(ASAttachmentConverter))] public List? Attachments { get; set; } + [J($"{Constants.ActivityStreamsNs}#replies")] + [JC(typeof(ASOrderedCollectionConverter))] + public ASOrderedCollection? Replies { get; set; } + public Note.NoteVisibility GetVisibility(User actor) { if (actor.IsLocalUser) throw new Exception("Can't get recipients for local actor");