diff --git a/api/api/v1/statuses/[id]/reactions/[name].test.ts b/api/api/v1/statuses/[id]/reactions/[name].test.ts index 9773ac3d..ccf0546a 100644 --- a/api/api/v1/statuses/[id]/reactions/[name].test.ts +++ b/api/api/v1/statuses/[id]/reactions/[name].test.ts @@ -1,11 +1,37 @@ -import { afterAll, describe, expect, test } from "bun:test"; +import { afterAll, beforeAll, describe, expect, test } from "bun:test"; +import { randomUUIDv7 } from "bun"; +import { Emoji } from "~/classes/database/emoji"; +import { Media } from "~/classes/database/media"; import { generateClient, getTestStatuses, getTestUsers } from "~/tests/utils"; const { users, deleteUsers } = await getTestUsers(3); const timeline = (await getTestStatuses(2, users[0])).toReversed(); +let emojiMedia: Media; +let customEmoji: Emoji; + +beforeAll(async () => { + emojiMedia = await Media.insert({ + id: randomUUIDv7(), + content: { + "image/png": { + content: "https://example.com/image.png", + remote: true, + }, + }, + }); + + customEmoji = await Emoji.insert({ + id: randomUUIDv7(), + shortcode: "test_emoji", + visibleInPicker: true, + mediaId: emojiMedia.id, + }); +}); afterAll(async () => { await deleteUsers(); + await customEmoji.delete(); + await emojiMedia.delete(); }); describe("/api/v1/statuses/:id/reactions/:name", () => { @@ -40,6 +66,29 @@ describe("/api/v1/statuses/:id/reactions/:name", () => { ); }); + test("should add custom emoji reaction", async () => { + await using client = await generateClient(users[1]); + + const { data, ok } = await client.createEmojiReaction( + timeline[0].id, + `:${customEmoji.data.shortcode}:`, + ); + + expect(ok).toBe(true); + expect(data.reactions).toContainEqual( + expect.objectContaining({ + name: `:${customEmoji.data.shortcode}:`, + count: 1, + me: true, + }), + ); + expect(data.emojis).toContainEqual( + expect.objectContaining({ + shortcode: customEmoji.data.shortcode, + }), + ); + }); + test("should add multiple different reactions", async () => { await using client1 = await generateClient(users[1]); await using client2 = await generateClient(users[2]); diff --git a/api/api/v1/statuses/[id]/reactions/[name].ts b/api/api/v1/statuses/[id]/reactions/[name].ts index ddaf8e8d..4070637b 100644 --- a/api/api/v1/statuses/[id]/reactions/[name].ts +++ b/api/api/v1/statuses/[id]/reactions/[name].ts @@ -105,19 +105,12 @@ export default apiRoute((app) => { emoji = unicodeEmoji; } - // Use the User react method - try { - await user.react(note, emoji); + await user.react(note, emoji); - // Reload note to get updated reactions - await note.reload(user.id); + // Reload note to get updated reactions + await note.reload(user.id); - return context.json(await note.toApi(user), 201); - } catch { - // If it's already reacted, just return the current status - await note.reload(user.id); - return context.json(await note.toApi(user), 201); - } + return context.json(await note.toApi(user), 201); }, ); @@ -206,7 +199,6 @@ export default apiRoute((app) => { emoji = unicodeEmoji; } - // Use the User unreact method await user.unreact(note, emoji); // Reload note to get updated reactions diff --git a/classes/database/note.ts b/classes/database/note.ts index 5b382879..2f2cba9f 100644 --- a/classes/database/note.ts +++ b/classes/database/note.ts @@ -641,6 +641,18 @@ export class Note extends BaseInterface { ); } + const reactions = this.getReactions(userFetching ?? undefined).map( + // Remove account_ids + (r) => ({ + ...r, + account_ids: undefined, + }), + ); + + const emojis = data.emojis.concat( + data.reactions.map((r) => r.emoji).filter((v) => v !== null), + ); + return { id: data.id, in_reply_to_id: data.replyId || null, @@ -652,7 +664,7 @@ export class Note extends BaseInterface { : undefined, card: null, content: replacedContent, - emojis: data.emojis.map((emoji) => new Emoji(emoji).toApi()), + emojis: emojis.map((emoji) => new Emoji(emoji).toApi()), favourited: data.liked, favourites_count: data.likeCount, media_attachments: (data.attachments ?? []).map((a) => @@ -699,13 +711,7 @@ export class Note extends BaseInterface { edited_at: data.updatedAt ? new Date(data.updatedAt).toISOString() : null, - reactions: this.getReactions(userFetching ?? undefined).map( - // Remove account_ids - (r) => ({ - ...r, - account_ids: undefined, - }), - ), + reactions, text: data.contentSource, }; }