From b13e0b0a544e38fe4453453b0b94680b8d02f19d Mon Sep 17 00:00:00 2001 From: ThatOneCalculator Date: Wed, 20 Sep 2023 22:42:37 -0700 Subject: [PATCH] Revert "refactor: :fire: remove legacy reactions" This reverts commit c119abc36cc8191640734e683173ca983a450c51. --- .../backend/src/misc/get-reaction-emoji.ts | 28 +++++++ packages/backend/src/misc/reaction-lib.ts | 59 ++++++++++++- .../src/models/repositories/note-reaction.ts | 7 +- .../backend/src/models/repositories/note.ts | 16 ++-- packages/backend/test/reaction-lib.ts | 83 +++++++++++++++++++ 5 files changed, 183 insertions(+), 10 deletions(-) create mode 100644 packages/backend/src/misc/get-reaction-emoji.ts create mode 100644 packages/backend/test/reaction-lib.ts diff --git a/packages/backend/src/misc/get-reaction-emoji.ts b/packages/backend/src/misc/get-reaction-emoji.ts new file mode 100644 index 0000000000..71521c4ae8 --- /dev/null +++ b/packages/backend/src/misc/get-reaction-emoji.ts @@ -0,0 +1,28 @@ +export default function (reaction: string): string { + switch (reaction) { + case "like": + return "👍"; + case "love": + return "❤️"; + case "laugh": + return "😆"; + case "hmm": + return "🤔"; + case "surprise": + return "😮"; + case "congrats": + return "🎉"; + case "angry": + return "💢"; + case "confused": + return "😥"; + case "rip": + return "😇"; + case "pudding": + return "🍮"; + case "star": + return "⭐"; + default: + return reaction; + } +} diff --git a/packages/backend/src/misc/reaction-lib.ts b/packages/backend/src/misc/reaction-lib.ts index 8dac9a98f9..e25b2d6614 100644 --- a/packages/backend/src/misc/reaction-lib.ts +++ b/packages/backend/src/misc/reaction-lib.ts @@ -4,11 +4,60 @@ import { Emojis } from "@/models/index.js"; import { toPunyNullable } from "./convert-host.js"; import { IsNull } from "typeorm"; +const legacies = new Map([ + ["like", "👍"], + ["love", "❤️"], + ["laugh", "😆"], + ["hmm", "🤔"], + ["surprise", "😮"], + ["congrats", "🎉"], + ["angry", "💢"], + ["confused", "😥"], + ["rip", "😇"], + ["pudding", "🍮"], + ["star", "⭐"], +]); + export async function getFallbackReaction() { const meta = await fetchMeta(); return meta.defaultReaction; } +export function convertLegacyReactions(reactions: Record) { + const _reactions = new Map(); + const decodedReactions = new Map(); + + for (const reaction in reactions) { + if (reactions[reaction] <= 0) continue; + + let decodedReaction; + if (decodedReactions.has(reaction)) { + decodedReaction = decodedReactions.get(reaction); + } else { + decodedReaction = decodeReaction(reaction); + decodedReactions.set(reaction, decodedReaction); + } + + let emoji = legacies.get(decodedReaction.reaction); + if (emoji) { + _reactions.set(emoji, (_reactions.get(emoji) || 0) + reactions[reaction]); + } else { + _reactions.set( + reaction, + (_reactions.get(reaction) || 0) + reactions[reaction], + ); + } + } + + const _reactions2 = new Map(); + for (const [reaction, count] of _reactions) { + const decodedReaction = decodedReactions.get(reaction); + _reactions2.set(decodedReaction.reaction, count); + } + + return Object.fromEntries(_reactions2); +} + export async function toDbReaction( reaction?: string | null, reacterHost?: string | null, @@ -17,7 +66,9 @@ export async function toDbReaction( reacterHost = toPunyNullable(reacterHost); - if (reaction === "♥️") return "❤️"; + // Convert string-type reactions to unicode + const emoji = legacies.get(reaction) || (reaction === "♥️" ? "❤️" : null); + if (emoji) return emoji; // Allow unicode reactions const match = emojiRegex.exec(reaction); @@ -77,3 +128,9 @@ export function decodeReaction(str: string): DecodedReaction { host: undefined, }; } + +export function convertLegacyReaction(reaction: string): string { + const decoded = decodeReaction(reaction).reaction; + if (legacies.has(decoded)) return legacies.get(decoded)!; + return decoded; +} diff --git a/packages/backend/src/models/repositories/note-reaction.ts b/packages/backend/src/models/repositories/note-reaction.ts index 852cc4fa84..6d1dfbd6fd 100644 --- a/packages/backend/src/models/repositories/note-reaction.ts +++ b/packages/backend/src/models/repositories/note-reaction.ts @@ -2,8 +2,8 @@ import { db } from "@/db/postgre.js"; import { NoteReaction } from "@/models/entities/note-reaction.js"; import { Notes, Users } from "../index.js"; import type { Packed } from "@/misc/schema.js"; +import { convertLegacyReaction } from "@/misc/reaction-lib.js"; import type { User } from "@/models/entities/user.js"; -import { decodeReaction } from "@/misc/reaction-lib.js"; export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ async pack( @@ -27,9 +27,10 @@ export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ id: reaction.id, createdAt: reaction.createdAt.toISOString(), user: await Users.pack(reaction.user ?? reaction.userId, me), - type: decodeReaction(reaction.reaction).reaction, + type: convertLegacyReaction(reaction.reaction), ...(opts.withNote ? { + // may throw error note: await Notes.pack(reaction.note ?? reaction.noteId, me), } : {}), @@ -40,7 +41,7 @@ export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ src: NoteReaction[], me?: { id: User["id"] } | null | undefined, options?: { - withNote: boolean; + withNote: booleam; }, ): Promise[]> { const reactions = await Promise.allSettled( diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index dcbc761cef..787601fefb 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -14,7 +14,11 @@ import { import type { Packed } from "@/misc/schema.js"; import { nyaize } from "@/misc/nyaize.js"; import { awaitAll } from "@/prelude/await-all.js"; -import { decodeReaction } from "@/misc/reaction-lib.js"; +import { + convertLegacyReaction, + convertLegacyReactions, + decodeReaction, +} from "@/misc/reaction-lib.js"; import type { NoteReaction } from "@/models/entities/note-reaction.js"; import { aggregateNoteEmojis, @@ -73,7 +77,7 @@ async function populateMyReaction( if (_hint_?.myReactions) { const reaction = _hint_.myReactions.get(note.id); if (reaction) { - return decodeReaction(reaction.reaction).reaction; + return convertLegacyReaction(reaction.reaction); } else if (reaction === null) { return undefined; } @@ -86,7 +90,7 @@ async function populateMyReaction( }); if (reaction) { - return decodeReaction(reaction.reaction).reaction; + return convertLegacyReaction(reaction.reaction); } return undefined; @@ -178,7 +182,7 @@ export const NoteRepository = db.getRepository(Note).extend({ let text = note.text; if (note.name && (note.url ?? note.uri)) { - text = `${note.name}\n${(note.text || "").trim()}\n\n${ + text = `【${note.name}】\n${(note.text || "").trim()}\n\n${ note.url ?? note.uri }`; } @@ -217,7 +221,7 @@ export const NoteRepository = db.getRepository(Note).extend({ note.visibility === "specified" ? note.visibleUserIds : undefined, renoteCount: note.renoteCount, repliesCount: note.repliesCount, - reactions: note.reactions, + reactions: convertLegacyReactions(note.reactions), reactionEmojis: reactionEmoji, emojis: noteEmoji, tags: note.tags.length > 0 ? note.tags : undefined, @@ -298,7 +302,7 @@ export const NoteRepository = db.getRepository(Note).extend({ if (meId) { const renoteIds = notes .filter((n) => n.renoteId != null) - .map((n) => n.renoteId); + .map((n) => n.renoteId!); const targets = [...notes.map((n) => n.id), ...renoteIds]; const myReactions = await NoteReactions.findBy({ userId: meId, diff --git a/packages/backend/test/reaction-lib.ts b/packages/backend/test/reaction-lib.ts new file mode 100644 index 0000000000..7c61dc76c2 --- /dev/null +++ b/packages/backend/test/reaction-lib.ts @@ -0,0 +1,83 @@ +/* +import * as assert from 'assert'; + +import { toDbReaction } from '../src/misc/reaction-lib.js'; + +describe('toDbReaction', async () => { + it('既存の文字列リアクションはそのまま', async () => { + assert.strictEqual(await toDbReaction('like'), 'like'); + }); + + it('Unicodeプリンは寿司化不能とするため文字列化しない', async () => { + assert.strictEqual(await toDbReaction('🍮'), '🍮'); + }); + + it('プリン以外の既存のリアクションは文字列化する like', async () => { + assert.strictEqual(await toDbReaction('👍'), 'like'); + }); + + it('プリン以外の既存のリアクションは文字列化する love', async () => { + assert.strictEqual(await toDbReaction('❤️'), 'love'); + }); + + it('プリン以外の既存のリアクションは文字列化する love 異体字セレクタなし', async () => { + assert.strictEqual(await toDbReaction('❤'), 'love'); + }); + + it('プリン以外の既存のリアクションは文字列化する laugh', async () => { + assert.strictEqual(await toDbReaction('😆'), 'laugh'); + }); + + it('プリン以外の既存のリアクションは文字列化する hmm', async () => { + assert.strictEqual(await toDbReaction('🤔'), 'hmm'); + }); + + it('プリン以外の既存のリアクションは文字列化する surprise', async () => { + assert.strictEqual(await toDbReaction('😮'), 'surprise'); + }); + + it('プリン以外の既存のリアクションは文字列化する congrats', async () => { + assert.strictEqual(await toDbReaction('🎉'), 'congrats'); + }); + + it('プリン以外の既存のリアクションは文字列化する angry', async () => { + assert.strictEqual(await toDbReaction('💢'), 'angry'); + }); + + it('プリン以外の既存のリアクションは文字列化する confused', async () => { + assert.strictEqual(await toDbReaction('😥'), 'confused'); + }); + + it('プリン以外の既存のリアクションは文字列化する rip', async () => { + assert.strictEqual(await toDbReaction('😇'), 'rip'); + }); + + it('それ以外はUnicodeのまま', async () => { + assert.strictEqual(await toDbReaction('🍅'), '🍅'); + }); + + it('異体字セレクタ除去', async () => { + assert.strictEqual(await toDbReaction('㊗️'), '㊗'); + }); + + it('異体字セレクタ除去 必要なし', async () => { + assert.strictEqual(await toDbReaction('㊗'), '㊗'); + }); + + it('fallback - undefined', async () => { + assert.strictEqual(await toDbReaction(undefined), 'like'); + }); + + it('fallback - null', async () => { + assert.strictEqual(await toDbReaction(null), 'like'); + }); + + it('fallback - empty', async () => { + assert.strictEqual(await toDbReaction(''), 'like'); + }); + + it('fallback - unknown', async () => { + assert.strictEqual(await toDbReaction('unknown'), 'like'); + }); +}); +*/