diff --git a/packages/backend/src/server/api/mastodon/converters/note.ts b/packages/backend/src/server/api/mastodon/converters/note.ts index 9b0ad43c6..bd92f5618 100644 --- a/packages/backend/src/server/api/mastodon/converters/note.ts +++ b/packages/backend/src/server/api/mastodon/converters/note.ts @@ -36,7 +36,10 @@ export class NoteConverter { const noteEmoji = host.then(async host => populateEmojis( note.emojis.concat(reactionEmojiNames), host, - )); + )) + .then(noteEmoji => noteEmoji + .filter((e) => e.name.indexOf("@") === -1) + .map((e) => EmojiConverter.encode(e))); const reactionCount = NoteReactions.countBy({ noteId: note.id }); @@ -110,10 +113,7 @@ export class NoteConverter { text: text, created_at: note.createdAt.toISOString(), // Remove reaction emojis with names containing @ from the emojis list. - emojis: noteEmoji - .then(noteEmoji => noteEmoji - .filter((e) => e.name.indexOf("@") === -1) - .map((e) => EmojiConverter.encode(e))), + emojis: noteEmoji, replies_count: note.repliesCount, reblogs_count: note.renoteCount, favourites_count: reactionCount, @@ -127,7 +127,7 @@ export class NoteConverter { mentions: mentions, tags: tags, card: null, //FIXME - poll: note.hasPoll ? populatePoll(note, user?.id ?? null).then(p => PollConverter.encode(p, note.id)) : null, + poll: note.hasPoll ? populatePoll(note, user?.id ?? null).then(p => noteEmoji.then(emojis => PollConverter.encode(p, note.id, emojis))) : null, application: null, //FIXME language: null, //FIXME pinned: isPinned, diff --git a/packages/backend/src/server/api/mastodon/converters/poll.ts b/packages/backend/src/server/api/mastodon/converters/poll.ts index adaefd997..211316b57 100644 --- a/packages/backend/src/server/api/mastodon/converters/poll.ts +++ b/packages/backend/src/server/api/mastodon/converters/poll.ts @@ -11,7 +11,7 @@ type Poll = { } export class PollConverter { - public static encode(p: Poll, noteId: string): MastodonEntity.Poll { + public static encode(p: Poll, noteId: string, emojis: MastodonEntity.Emoji[]): MastodonEntity.Poll { const now = new Date(); const count = p.choices.reduce((sum, choice) => sum + choice.votes, 0); return { @@ -21,6 +21,7 @@ export class PollConverter { multiple: p.multiple, votes_count: count, options: p.choices.map((c) => this.encodeChoice(c)), + emojis: emojis, voted: p.choices.some((c) => c.isVoted), own_votes: p.choices .filter((c) => c.isVoted) diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index f63b14d60..2b25bdb23 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -268,7 +268,7 @@ export function setupEndpointsStatus(router: Router): void { async (ctx) => { const id = convertId(ctx.params.id, IdType.IceshrimpId); const note = await NoteHelpers.getNoteOr404(id, ctx.user); - const data = await PollHelpers.getPoll(note, ctx.user); + const data = await PollHelpers.getPoll(note, ctx.user, ctx.cache); ctx.body = convertPollId(data); }); router.post<{ Params: { id: string } }>( @@ -286,7 +286,7 @@ export function setupEndpointsStatus(router: Router): void { return; } - const data = await PollHelpers.voteInPoll(choices, note, ctx.user); + const data = await PollHelpers.voteInPoll(choices, note, ctx.user, ctx.cache); ctx.body = convertPollId(data); }, ); diff --git a/packages/backend/src/server/api/mastodon/entities/poll.ts b/packages/backend/src/server/api/mastodon/entities/poll.ts index 1183ddab6..6eefdbc74 100644 --- a/packages/backend/src/server/api/mastodon/entities/poll.ts +++ b/packages/backend/src/server/api/mastodon/entities/poll.ts @@ -10,5 +10,6 @@ namespace MastodonEntity { options: Array; voted: boolean; own_votes: Array; + emojis: Array; }; } diff --git a/packages/backend/src/server/api/mastodon/helpers/poll.ts b/packages/backend/src/server/api/mastodon/helpers/poll.ts index 2280e082f..23616146f 100644 --- a/packages/backend/src/server/api/mastodon/helpers/poll.ts +++ b/packages/backend/src/server/api/mastodon/helpers/poll.ts @@ -2,7 +2,7 @@ import { Note } from "@/models/entities/note.js"; import { populatePoll } from "@/models/repositories/note.js"; import { PollConverter } from "@/server/api/mastodon/converters/poll.js"; import { ILocalUser, IRemoteUser } from "@/models/entities/user.js"; -import { Blockings, NoteWatchings, Polls, PollVotes, Users } from "@/models/index.js"; +import { Blockings, Notes, NoteWatchings, Polls, PollVotes, Users } from "@/models/index.js"; import { genId } from "@/misc/gen-id.js"; import { publishNoteStream } from "@/services/stream.js"; import { createNotification } from "@/services/create-notification.js"; @@ -11,13 +11,27 @@ import { renderActivity } from "@/remote/activitypub/renderer/index.js"; import renderVote from "@/remote/activitypub/renderer/vote.js"; import { Not } from "typeorm"; import { MastoApiError } from "@/server/api/mastodon/middleware/catch-errors.js"; +import { populateEmojis } from "@/misc/populate-emojis.js"; +import { EmojiConverter } from "@/server/api/mastodon/converters/emoji.js"; +import { AccountCache, UserHelpers } from "@/server/api/mastodon/helpers/user.js"; export class PollHelpers { - public static async getPoll(note: Note, user: ILocalUser | null): Promise { - return populatePoll(note, user?.id ?? null).then(p => PollConverter.encode(p, note.id)); + public static async getPoll(note: Note, user: ILocalUser | null, cache: AccountCache = UserHelpers.getFreshAccountCache()): Promise { + if (!await Notes.isVisibleForMe(note, user?.id ?? null)) + throw new Error('Cannot encode poll not visible for user'); + + const noteUser = note.user ?? UserHelpers.getUserCached(note.userId, cache); + const host = Promise.resolve(noteUser).then(noteUser => noteUser.host ?? null); + const noteEmoji = await host + .then(async host => populateEmojis(note.emojis, host) + .then(noteEmoji => noteEmoji + .filter((e) => e.name.indexOf("@") === -1) + .map((e) => EmojiConverter.encode(e)))); + + return populatePoll(note, user?.id ?? null).then(p => PollConverter.encode(p, note.id, noteEmoji)); } - public static async voteInPoll(choices: number[], note: Note, user: ILocalUser): Promise { + public static async voteInPoll(choices: number[], note: Note, user: ILocalUser, cache: AccountCache = UserHelpers.getFreshAccountCache()): Promise { if (!note.hasPoll) throw new MastoApiError(404); for (const choice of choices) { @@ -108,6 +122,6 @@ export class PollHelpers { ); } } - return this.getPoll(note, user); + return this.getPoll(note, user, cache); } }