diff --git a/Iceshrimp.Backend/Core/Configuration/Constants.cs b/Iceshrimp.Backend/Core/Configuration/Constants.cs index ffe53b1f..3cbe6d15 100644 --- a/Iceshrimp.Backend/Core/Configuration/Constants.cs +++ b/Iceshrimp.Backend/Core/Configuration/Constants.cs @@ -8,6 +8,7 @@ public static class Constants public const string XsdNs = "http://www.w3.org/2001/XMLSchema"; public const string SchemaNs = "http://schema.org"; public const string MastodonNs = "http://joinmastodon.org/ns"; + public const string MisskeyNs = "https://misskey-hub.net/ns"; public static readonly string[] SystemUsers = ["instance.actor", "relay.actor"]; public static readonly string[] BrowserSafeMimeTypes = diff --git a/Iceshrimp.Backend/Core/Federation/ActivityPub/ActivityHandlerService.cs b/Iceshrimp.Backend/Core/Federation/ActivityPub/ActivityHandlerService.cs index d5743eae..bb799d15 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityPub/ActivityHandlerService.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityPub/ActivityHandlerService.cs @@ -144,11 +144,13 @@ public class ActivityHandlerService( case ASFollow { Object: ASActor followee }: await UnfollowAsync(followee, resolvedActor); return; - case ASLike { Object: ASNote likedNote }: - await noteSvc.UnlikeNoteAsync(likedNote, resolvedActor); + case ASLike { Object: ASNote note } like: + var dbNote = await noteSvc.UnlikeNoteAsync(note, resolvedActor); + if (like.MisskeyReaction != null) + await noteSvc.RemoveReactionFromNoteAsync(dbNote, resolvedActor, like.MisskeyReaction); return; - case ASAnnounce { Object: ASNote likedNote }: - await noteSvc.UndoAnnounceAsync(likedNote, resolvedActor); + case ASAnnounce { Object: ASNote note }: + await noteSvc.UndoAnnounceAsync(note, resolvedActor); return; case ASEmojiReact { Object: ASNote note } react: await noteSvc.RemoveReactionFromNoteAsync(note, resolvedActor, react.Content); @@ -157,11 +159,18 @@ public class ActivityHandlerService( throw GracefulException.UnprocessableEntity("Undo activity object is invalid"); } } - case ASLike: + case ASLike like: { if (activity.Object is not ASNote note) throw GracefulException.UnprocessableEntity("Like activity object is invalid"); - await noteSvc.LikeNoteAsync(note, resolvedActor); + var dbNote = await noteSvc.LikeNoteAsync(note, resolvedActor); + + if (like.MisskeyReaction != null) + { + await emojiSvc.ProcessEmojiAsync(like.Tags?.OfType().ToList(), resolvedActor.Host); + await noteSvc.ReactToNoteAsync(dbNote, resolvedActor, like.MisskeyReaction); + } + return; } case ASUpdate: diff --git a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs index 9db08183..7656cbad 100644 --- a/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs +++ b/Iceshrimp.Backend/Core/Federation/ActivityStreams/Types/ASActivity.cs @@ -119,6 +119,14 @@ public class ASUndo : ASActivity public class ASLike : ASActivity { public ASLike() => Type = Types.Like; + + [J($"{Constants.MisskeyNs}#_misskey_reaction")] + [JC(typeof(VC))] + public string? MisskeyReaction { get; set; } + + [J($"{Constants.ActivityStreamsNs}#tag")] + [JC(typeof(ASTagConverter))] + public List? Tags { get; set; } } public class ASUpdate : ASActivity diff --git a/Iceshrimp.Backend/Core/Services/NoteService.cs b/Iceshrimp.Backend/Core/Services/NoteService.cs index 9e8956ae..5b116ac3 100644 --- a/Iceshrimp.Backend/Core/Services/NoteService.cs +++ b/Iceshrimp.Backend/Core/Services/NoteService.cs @@ -1041,16 +1041,18 @@ public class NoteService( return true; } - public async Task LikeNoteAsync(ASNote note, User actor) + public async Task LikeNoteAsync(ASNote note, User actor) { var dbNote = await ResolveNoteAsync(note) ?? throw new Exception("Cannot register like for unknown note"); await LikeNoteAsync(dbNote, actor); + return dbNote; } - public async Task UnlikeNoteAsync(ASNote note, User user) + public async Task UnlikeNoteAsync(ASNote note, User user) { var dbNote = await ResolveNoteAsync(note) ?? throw new Exception("Cannot unregister like for unknown note"); await UnlikeNoteAsync(dbNote, user); + return dbNote; } public async Task BookmarkNoteAsync(Note note, User user)