import { ActionRowBuilder, APIEmbedField, ButtonBuilder, ButtonStyle, Client, DiscordAPIError, EmbedBuilder, Message } from 'discord.js'; import { config } from '../config'; import { Database } from '../shared/Database'; import { Appeal, AppealUpdate, E621Post, PostFlag } from '../types'; import { getAuthor, getColor, parseMarkdownToField, getFields } from './event-utils'; import { humanizeCapitalization } from './string-utils'; import { getE621Post, getE621PostFlag, PostAction, spoilerOrBlacklist } from './e621-utils'; import { parseDTextToMarkdown } from './dtext-utils'; export async function appealUpdateHandler(client: Client, update: string) { const data: AppealUpdate = JSON.parse(update); if (data.action == 'create') { postAppeal(client, data); } else { updateAppeal(client, data); } } async function postAppeal(client: Client, data: AppealUpdate) { const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!); if (!guildSettings || !guildSettings.appeals_channel_id) return; const channel = await client.channels.fetch(guildSettings.appeals_channel_id); if (!channel || !channel.isSendable()) return; const appeal = data.appeal; const flag = await getE621PostFlag(appeal.target_id); const post = await getE621Post(flag!.post_id); const embed = await createEmbedFromAppeal(appeal, flag!, post!); const row = await getButtons(appeal, flag!, post!); const message = await channel.send({ embeds: [embed], components: row.components.length > 0 ? [row] : [] }); await Database.putAppealOrUpdate(appeal.id, message.id); } async function updateAppeal(client: Client, data: AppealUpdate) { const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!); if (!guildSettings || !guildSettings.appeals_channel_id) return; const channel = await client.channels.fetch(guildSettings.appeals_channel_id); if (!channel || !channel.isSendable()) return; const messageId = await Database.getAppealMessageId(data.appeal.id); if (!messageId) return postAppeal(client, data); let message: Message | undefined; try { message = await channel.messages.fetch(messageId); } catch (e) { // Ignore unknown message errors if (!(e instanceof DiscordAPIError && e.code == 10008)) { throw e; } } if (!message || message.author.id != config.DISCORD_CLIENT_ID) return postAppeal(client, data); const flag = await getE621PostFlag(data.appeal.target_id); const post = await getE621Post(flag!.post_id); const embed = await createEmbedFromAppeal(data.appeal, flag!, post!); await message.edit({ embeds: [embed] }); } function getTitle(appeal: Appeal): string { if (!appeal.target) return `${humanizeCapitalization(appeal.category)} appeal from ${appeal.user}`; switch (appeal.category) { case 'flag': return `Flag by ${appeal.target}`; default: return 'Uknown appeal category'; } } function getURL(appeal: Appeal): string { return `${config.E621_BASE_URL}/appeals/${appeal.id}`; } async function getCustomFields(appeal: Appeal, flag: PostFlag, post: E621Post): Promise { return [ { name: 'Deletion Reason', value: await parseDTextToMarkdown(flag.reason), inline: true } ]; } async function createEmbedFromAppeal(appeal: Appeal, flag: PostFlag, post: E621Post): Promise { return new EmbedBuilder() .setTitle(getTitle(appeal)) .setURL(await getURL(appeal)) .setAuthor(getAuthor(appeal)) .setColor(getColor(appeal)) .setFields( { name: 'Reason', value: await parseMarkdownToField(appeal.reason), inline: false }, ...getFields(appeal), ...(await getCustomFields(appeal, flag, post)) ) .setFooter({ text: `Appeal #${appeal.id}` }); } async function getButtons(appeal: Appeal, flag: PostFlag, post: E621Post): Promise> { const row = new ActionRowBuilder(); if (spoilerOrBlacklist(post).action != PostAction.Blacklist) { const button = new ButtonBuilder() .setLabel('Open Post') .setStyle(ButtonStyle.Link) .setURL(`${config.E621_BASE_URL}/posts/${post.id}`); row.addComponents(button); } return row; }