Update ticket and appeal handlers
This commit is contained in:
@@ -282,6 +282,18 @@ export class Database {
|
|||||||
await Database.db.run('INSERT INTO tickets(id, message_id) VALUES (?, ?)', ticketId, messageId);
|
await Database.db.run('INSERT INTO tickets(id, message_id) VALUES (?, ?)', ticketId, messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async updateTicketMessageId(ticketId: number, messageId: string) {
|
||||||
|
await Database.db.run('UPDATE tickets SET message_id = ? WHERE id = ?', messageId, ticketId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async putTicketOrUpdate(ticketId: number, messageId: string) {
|
||||||
|
if (await Database.getTicketMessageId(ticketId)) {
|
||||||
|
await Database.updateTicketMessageId(ticketId, messageId);
|
||||||
|
} else {
|
||||||
|
await Database.putTicket(ticketId, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async removeTicket(ticketId: number) {
|
static async removeTicket(ticketId: number) {
|
||||||
await Database.db.run('DELETE from tickets WHERE id = ?', ticketId);
|
await Database.db.run('DELETE from tickets WHERE id = ?', ticketId);
|
||||||
}
|
}
|
||||||
@@ -327,6 +339,18 @@ export class Database {
|
|||||||
await Database.db.run('INSERT INTO appeals(id, message_id) VALUES (?, ?)', appealId, messageId);
|
await Database.db.run('INSERT INTO appeals(id, message_id) VALUES (?, ?)', appealId, messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async updateAppealMessageId(appealId: number, messageId: string) {
|
||||||
|
await Database.db.run('UPDATE appeals SET message_id = ? WHERE id = ?', messageId, appealId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async putAppealOrUpdate(ticketId: number, messageId: string) {
|
||||||
|
if (await Database.getAppealMessageId(ticketId)) {
|
||||||
|
await Database.updateAppealMessageId(ticketId, messageId);
|
||||||
|
} else {
|
||||||
|
await Database.putAppeal(ticketId, messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async removeAppeal(appealId: number) {
|
static async removeAppeal(appealId: number) {
|
||||||
await Database.db.run('DELETE from appeals WHERE id = ?', appealId);
|
await Database.db.run('DELETE from appeals WHERE id = ?', appealId);
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+16
@@ -172,4 +172,20 @@ export type Record = {
|
|||||||
updated_at: string
|
updated_at: string
|
||||||
updater_id: number
|
updater_id: number
|
||||||
is_deleted: boolean
|
is_deleted: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PostFlag = {
|
||||||
|
id: number
|
||||||
|
post_id: number
|
||||||
|
creator_id: number
|
||||||
|
reason: string
|
||||||
|
is_resolved: boolean
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
is_deletion: boolean
|
||||||
|
note: string | null
|
||||||
|
reason_name: string
|
||||||
|
needs_parent_id: boolean
|
||||||
|
needs_staff_reason: boolean
|
||||||
|
type: string
|
||||||
}
|
}
|
||||||
+45
-16
@@ -1,9 +1,10 @@
|
|||||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Client, EmbedBuilder } from 'discord.js';
|
import { ActionRowBuilder, APIEmbedField, ButtonBuilder, ButtonStyle, Client, DiscordAPIError, EmbedBuilder, Message } from 'discord.js';
|
||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
import { Appeal, AppealUpdate } from '../types';
|
import { Appeal, AppealUpdate, E621Post, PostFlag } from '../types';
|
||||||
import { getAuthor, getColor, getDescription, getFields } from './event-utils';
|
import { getAuthor, getColor, getDescription, getFields } from './event-utils';
|
||||||
import { humanizeCapitalization } from './string-utils';
|
import { humanizeCapitalization } from './string-utils';
|
||||||
|
import { getE621Post, getE621PostFlag } from './e621-utils';
|
||||||
|
|
||||||
export async function appealUpdateHandler(client: Client, update: string) {
|
export async function appealUpdateHandler(client: Client, update: string) {
|
||||||
const data: AppealUpdate = JSON.parse(update);
|
const data: AppealUpdate = JSON.parse(update);
|
||||||
@@ -26,13 +27,16 @@ async function postAppeal(client: Client, data: AppealUpdate) {
|
|||||||
|
|
||||||
const appeal = data.appeal;
|
const appeal = data.appeal;
|
||||||
|
|
||||||
const embed = await createEmbedFromAppeal(appeal);
|
const flag = await getE621PostFlag(appeal.target_id);
|
||||||
|
const post = await getE621Post(flag!.post_id);
|
||||||
|
|
||||||
const row = await getButtons(appeal);
|
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] : [] });
|
const message = await channel.send({ embeds: [embed], components: row.components.length > 0 ? [row] : [] });
|
||||||
|
|
||||||
await Database.putAppeal(appeal.id, message.id);
|
await Database.putAppealOrUpdate(appeal.id, message.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateAppeal(client: Client, data: AppealUpdate) {
|
async function updateAppeal(client: Client, data: AppealUpdate) {
|
||||||
@@ -48,16 +52,24 @@ async function updateAppeal(client: Client, data: AppealUpdate) {
|
|||||||
|
|
||||||
if (!messageId) return postAppeal(client, data);
|
if (!messageId) return postAppeal(client, data);
|
||||||
|
|
||||||
const message = await channel.messages.fetch(messageId);
|
let message: Message | undefined;
|
||||||
const embed = await createEmbedFromAppeal(data.appeal);
|
|
||||||
|
|
||||||
if (!message || message.author.id != config.DISCORD_CLIENT_ID) {
|
try {
|
||||||
const newMessage = await channel.send({ embeds: [embed] });
|
message = await channel.messages.fetch(messageId);
|
||||||
await Database.removeAppeal(data.appeal.id);
|
} catch (e) {
|
||||||
await Database.putAppeal(data.appeal.id, newMessage.id);
|
// Ignore unknown message errors
|
||||||
} else {
|
if (!(e instanceof DiscordAPIError && e.code == 10008)) {
|
||||||
await message.edit({ embeds: [embed] });
|
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 {
|
function getTitle(appeal: Appeal): string {
|
||||||
@@ -75,18 +87,28 @@ function getURL(appeal: Appeal): string {
|
|||||||
return `${config.E621_BASE_URL}/appeals/${appeal.id}`;
|
return `${config.E621_BASE_URL}/appeals/${appeal.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createEmbedFromAppeal(appeal: Appeal): Promise<EmbedBuilder> {
|
function getCustomFields(appeal: Appeal, flag: PostFlag, post: E621Post): APIEmbedField[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'Deletion Reason',
|
||||||
|
value: flag.reason,
|
||||||
|
inline: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createEmbedFromAppeal(appeal: Appeal, flag: PostFlag, post: E621Post): Promise<EmbedBuilder> {
|
||||||
return new EmbedBuilder()
|
return new EmbedBuilder()
|
||||||
.setTitle(getTitle(appeal))
|
.setTitle(getTitle(appeal))
|
||||||
.setURL(await getURL(appeal))
|
.setURL(await getURL(appeal))
|
||||||
.setDescription(await getDescription(appeal))
|
.setDescription(await getDescription(appeal))
|
||||||
.setAuthor(getAuthor(appeal))
|
.setAuthor(getAuthor(appeal))
|
||||||
.setColor(getColor(appeal))
|
.setColor(getColor(appeal))
|
||||||
.setFields(...getFields(appeal))
|
.setFields(...getFields(appeal), ...getCustomFields(appeal, flag, post))
|
||||||
.setFooter({ text: `Appeal #${appeal.id}` });
|
.setFooter({ text: `Appeal #${appeal.id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getButtons(appeal: Appeal): Promise<ActionRowBuilder<ButtonBuilder>> {
|
async function getButtons(appeal: Appeal, flag: PostFlag, post: E621Post): Promise<ActionRowBuilder<ButtonBuilder>> {
|
||||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
const row = new ActionRowBuilder<ButtonBuilder>();
|
||||||
|
|
||||||
const primaryButton = new ButtonBuilder()
|
const primaryButton = new ButtonBuilder()
|
||||||
@@ -100,5 +122,12 @@ async function getButtons(appeal: Appeal): Promise<ActionRowBuilder<ButtonBuilde
|
|||||||
row.addComponents(primaryButton);
|
row.addComponents(primaryButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const button = new ButtonBuilder()
|
||||||
|
.setLabel('Open Post')
|
||||||
|
.setStyle(ButtonStyle.Link)
|
||||||
|
.setURL(`${config.E621_BASE_URL}/posts/${post.id}`);
|
||||||
|
|
||||||
|
row.addComponents(button);
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { formatMarkdown, parseDTextToAST } from '@clynamic/dmark';
|
|
||||||
|
|
||||||
export function dtextToMarkdown(dtext: string): string {
|
|
||||||
return formatMarkdown(parseDTextToAST(dtext)).output;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
import { E621Post, E621User, Record } from '../types';
|
import { E621Post, E621User, PostFlag, Record } from '../types';
|
||||||
|
|
||||||
const BLACKLISTED_TAGS: string[] = [];
|
const BLACKLISTED_TAGS: string[] = [];
|
||||||
const BLACKLISTED_NONSAFE_TAGS: string[] = ['young'];
|
const BLACKLISTED_NONSAFE_TAGS: string[] = ['young'];
|
||||||
@@ -35,11 +35,15 @@ export async function getE621User(idOrName: string | number): Promise<E621User |
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getE621Post(id: string | number): Promise<E621Post | null> {
|
export async function getE621Post(id: string | number): Promise<E621Post | null> {
|
||||||
return (await request(`/posts/${id}`))?.post as E621Post ?? null;
|
return (await request(`/posts/${id}`, { v2: 'true' })) as E621Post ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getE621PostByMd5(md5: string): Promise<E621Post | null> {
|
export async function getE621PostByMd5(md5: string): Promise<E621Post | null> {
|
||||||
return (await request('/posts', { md5 }))?.post as E621Post ?? null;
|
return (await request('/posts', { md5, v2: 'true' })) as E621Post ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getE621PostFlag(id: number): Promise<PostFlag | null> {
|
||||||
|
return await request(`/post_flags/${id}`) as PostFlag ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum PostAction {
|
export const enum PostAction {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { APIEmbedField, EmbedAuthorOptions } from 'discord.js';
|
|||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
import { getE621Post, PostAction, spoilerOrBlacklist } from './e621-utils';
|
import { getE621Post, PostAction, spoilerOrBlacklist } from './e621-utils';
|
||||||
import { appealIDRegex, blipIDRegex, commentIDRegex, flagIDRegex, forumTopicIDRegex, poolIDRegex, postIDRegex, recordIDRegex, searchLinkRegex, setIDRegex, takedownIDRegex, ticketIDRegex, userIDRegex, wikiLinkRegex } from './message-matcher-regex';
|
import { appealIDRegex, blipIDRegex, commentIDRegex, flagIDRegex, forumTopicIDRegex, poolIDRegex, postIDRegex, recordIDRegex, searchLinkRegex, setIDRegex, takedownIDRegex, ticketIDRegex, userIDRegex, wikiLinkRegex } from './message-matcher-regex';
|
||||||
import { dtextToMarkdown } from './dtext-utils';
|
import { parseDTextToMarkdown } from '@clynamic/dmark';
|
||||||
|
|
||||||
// TODO: Condense this and the message event handler regex array.
|
// TODO: Condense this and the message event handler regex array.
|
||||||
const linkReplacers = [
|
const linkReplacers = [
|
||||||
@@ -135,7 +135,7 @@ export async function getLinks(input: string, limit: number = Number.MAX_SAFE_IN
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getDescription(data: { reason: string }): Promise<string> {
|
export async function getDescription(data: { reason: string }): Promise<string> {
|
||||||
return dtextToMarkdown(data.reason.length <= MAX_DESCRIPTION_LENGTH ? await getLinks(data.reason) : await getLinks(data.reason, MAX_DESCRIPTION_LENGTH));
|
return parseDTextToMarkdown(data.reason.length <= MAX_DESCRIPTION_LENGTH ? await getLinks(data.reason) : await getLinks(data.reason, MAX_DESCRIPTION_LENGTH)).output;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAuthor(data: { user_id: number, user: string }): EmbedAuthorOptions {
|
export function getAuthor(data: { user_id: number, user: string }): EmbedAuthorOptions {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export * from './channel-utils';
|
|||||||
export * from './commands';
|
export * from './commands';
|
||||||
export * from './debug-utils';
|
export * from './debug-utils';
|
||||||
export * from './discord-user-utils';
|
export * from './discord-user-utils';
|
||||||
export * from './dtext-utils';
|
|
||||||
export * from './e621-utils';
|
export * from './e621-utils';
|
||||||
export * from './embed-utils';
|
export * from './embed-utils';
|
||||||
export * from './event-log-utils';
|
export * from './event-log-utils';
|
||||||
|
|||||||
+16
-10
@@ -1,4 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Client, EmbedBuilder, SendableChannels } from 'discord.js';
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Client, DiscordAPIError, EmbedBuilder, Message, SendableChannels } from 'discord.js';
|
||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
import { Ticket, TicketPhrase, TicketUpdate } from '../types';
|
import { Ticket, TicketPhrase, TicketUpdate } from '../types';
|
||||||
@@ -34,7 +34,7 @@ async function postTicket(client: Client, data: TicketUpdate) {
|
|||||||
|
|
||||||
const message = await channel.send({ embeds: [embed], components: [row] });
|
const message = await channel.send({ embeds: [embed], components: [row] });
|
||||||
|
|
||||||
await Database.putTicket(ticket.id, message.id);
|
await Database.putTicketOrUpdate(ticket.id, message.id);
|
||||||
|
|
||||||
sendTicketAlerts(ticket, channel);
|
sendTicketAlerts(ticket, channel);
|
||||||
}
|
}
|
||||||
@@ -52,16 +52,22 @@ async function updateTicket(client: Client, data: TicketUpdate) {
|
|||||||
|
|
||||||
if (!messageId) return postTicket(client, data);
|
if (!messageId) return postTicket(client, data);
|
||||||
|
|
||||||
const message = await channel.messages.fetch(messageId);
|
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 postTicket(client, data);
|
||||||
|
|
||||||
const embed = await createEmbedFromTicket(data.ticket);
|
const embed = await createEmbedFromTicket(data.ticket);
|
||||||
|
|
||||||
if (!message || message.author.id != config.DISCORD_CLIENT_ID) {
|
await message.edit({ embeds: [embed] });
|
||||||
const newMessage = await channel.send({ embeds: [embed] });
|
|
||||||
await Database.removeTicket(data.ticket.id);
|
|
||||||
await Database.putTicket(data.ticket.id, newMessage.id);
|
|
||||||
} else {
|
|
||||||
await message.edit({ embeds: [embed] });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTitle(ticket: Ticket): string {
|
function getTitle(ticket: Ticket): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user