Restructure redis client
This commit is contained in:
+4
-333
@@ -1,82 +1,6 @@
|
|||||||
import { createClient } from '@redis/client';
|
import { createClient } from '@redis/client';
|
||||||
import { Database } from './Database';
|
import { Client } from 'discord.js';
|
||||||
import { config } from '../config';
|
import { banUpdateHandler, ticketUpdateHandler } from '../utils';
|
||||||
import { APIEmbedField, Client, EmbedAuthorOptions, EmbedBuilder, SendableChannels, TextBasedChannel } from 'discord.js';
|
|
||||||
import { blipIDRegex, commentIDRegex, forumTopicIDRegex, humanizeCapitalization, poolIDRegex, postIDRegex, shouldAlert, recordIDRegex, searchLinkRegex, setIDRegex, takedownIDRegex, ticketIDRegex, userIDRegex, wikiLinkRegex, getE621Post, spoilerOrBlacklist, PostAction } from '../utils';
|
|
||||||
import { BanUpdate, Ticket, TicketPhrase, TicketUpdate } from '../types';
|
|
||||||
|
|
||||||
// TODO: Condense this and the message event handler regex array.
|
|
||||||
const linkReplacers = [
|
|
||||||
{
|
|
||||||
regex: blipIDRegex,
|
|
||||||
replacement: '/blips/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: commentIDRegex,
|
|
||||||
replacement: '/comments/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: forumTopicIDRegex,
|
|
||||||
replacement: '/forum_topics/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: poolIDRegex,
|
|
||||||
replacement: '/pools/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: postIDRegex,
|
|
||||||
tester: async (postId: string, before: string, after: string) => {
|
|
||||||
const post = await getE621Post(postId);
|
|
||||||
if (!post) return { allowed: true, before, after };
|
|
||||||
const allowed = spoilerOrBlacklist(post).action != PostAction.Blacklist;
|
|
||||||
|
|
||||||
return { allowed, before, after };
|
|
||||||
},
|
|
||||||
replacement: '/posts/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: recordIDRegex,
|
|
||||||
replacement: '/user_feedbacks/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: searchLinkRegex,
|
|
||||||
replacement: '/posts?tags={match}',
|
|
||||||
encodeURI: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: setIDRegex,
|
|
||||||
replacement: '/post_sets/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: takedownIDRegex,
|
|
||||||
replacement: '/takedowns/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: ticketIDRegex,
|
|
||||||
replacement: '/tickets/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: userIDRegex,
|
|
||||||
replacement: '/users/{match}',
|
|
||||||
encodeURI: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
regex: wikiLinkRegex,
|
|
||||||
replacement: '/wiki_pages/{match}',
|
|
||||||
encodeURI: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const MAX_DESCRIPTION_LENGTH = 500;
|
|
||||||
|
|
||||||
let discordClient: Client;
|
let discordClient: Client;
|
||||||
|
|
||||||
@@ -100,261 +24,8 @@ export async function openRedisClient(url: string, discClient: Client) {
|
|||||||
function updateHandler(data: string, channel: string) {
|
function updateHandler(data: string, channel: string) {
|
||||||
switch (channel) {
|
switch (channel) {
|
||||||
case 'ticket_updates':
|
case 'ticket_updates':
|
||||||
return ticketUpdateHandler(data);
|
return ticketUpdateHandler(discordClient, data);
|
||||||
case 'ban_updates':
|
case 'ban_updates':
|
||||||
return banUpdateHandler(data);
|
return banUpdateHandler(discordClient, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function banUpdateHandler(update: string) {
|
|
||||||
const data: BanUpdate = JSON.parse(update);
|
|
||||||
|
|
||||||
if (data.action == 'create') {
|
|
||||||
kickDiscordAccounts(data);
|
|
||||||
}
|
|
||||||
// else if (data.action == 'delete') {
|
|
||||||
// // unbanDiscordAccounts(data);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
async function kickDiscordAccounts(data: BanUpdate) {
|
|
||||||
const guild = await discordClient.guilds.fetch(config.DISCORD_GUILD_ID!);
|
|
||||||
|
|
||||||
const discordIds = await Database.getDiscordIds(data.ban.user_id);
|
|
||||||
|
|
||||||
for (const id of discordIds) {
|
|
||||||
const member = await guild.members.fetch(id);
|
|
||||||
|
|
||||||
if (member) await member.kick(`Banned from e621 by: https://e621.net/users/${data.ban.banner_id}. Reason:\n${data.ban.reason}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// async function banDiscordAccounts(data: BanUpdate) {
|
|
||||||
// const guild = await discordClient.guilds.fetch(config.DISCORD_GUILD_ID!);
|
|
||||||
|
|
||||||
// const discordIds = await Database.getDiscordIds(data.ban.user_id);
|
|
||||||
|
|
||||||
// for (const id of discordIds) {
|
|
||||||
// await guild.bans.create(id, {
|
|
||||||
// reason: data.ban.reason
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function unbanDiscordAccounts(data: BanUpdate) {
|
|
||||||
// const guild = await discordClient.guilds.fetch(config.DISCORD_GUILD_ID!);
|
|
||||||
|
|
||||||
// const discordIds = await Database.getDiscordIds(data.ban.user_id);
|
|
||||||
|
|
||||||
// for (const id of discordIds) {
|
|
||||||
// await guild.bans.remove(id);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
async function ticketUpdateHandler(update: string) {
|
|
||||||
const data: TicketUpdate = JSON.parse(update);
|
|
||||||
|
|
||||||
if (data.action == 'create') {
|
|
||||||
postTicket(data);
|
|
||||||
} else {
|
|
||||||
updateTicket(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTitle(ticket: Ticket): string {
|
|
||||||
if (!ticket.target) return `${humanizeCapitalization(ticket.category)} report by ${ticket.user}`;
|
|
||||||
|
|
||||||
switch (ticket.category) {
|
|
||||||
case 'blip':
|
|
||||||
return `Blip by ${ticket.target}`;
|
|
||||||
case 'comment':
|
|
||||||
return `Comment by ${ticket.target}`;
|
|
||||||
case 'dmail':
|
|
||||||
return `DMail sent by ${ticket.target}`;
|
|
||||||
case 'forum':
|
|
||||||
return `Forum post by ${ticket.target}`;
|
|
||||||
case 'pool':
|
|
||||||
return `Pool ${ticket.target}`;
|
|
||||||
case 'post':
|
|
||||||
return `Post uploaded by ${ticket.target}`;
|
|
||||||
case 'set':
|
|
||||||
return `Wow, a rare set report! ${ticket.target}`;
|
|
||||||
case 'user':
|
|
||||||
return `User ${ticket.target}`;
|
|
||||||
case 'wiki':
|
|
||||||
return `Wiki page ${ticket.target}`;
|
|
||||||
default:
|
|
||||||
return 'Uknown ticket category';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getURL(ticket: Ticket): string {
|
|
||||||
return `${config.E621_BASE_URL}/tickets/${ticket.id}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLinks(input: string, limit: number = Number.MAX_SAFE_INTEGER): Promise<string> {
|
|
||||||
const length = input.length;
|
|
||||||
|
|
||||||
const replacedIndexes: { start: number, end: number }[] = [];
|
|
||||||
const checks: Promise<{ allowed: boolean, before: string, after: string }>[] = [];
|
|
||||||
|
|
||||||
for (const replacer of linkReplacers) {
|
|
||||||
input = input.replaceAll(replacer.regex, (match, group1) => {
|
|
||||||
const replaced = `[${match}](${config.E621_BASE_URL}${(replacer.replacement).replace('{match}', replacer.encodeURI ? encodeURIComponent(group1) : group1)})`;
|
|
||||||
if (replacer.tester) checks.push(replacer.tester(group1, match, replaced));
|
|
||||||
const start = input.indexOf(match);
|
|
||||||
replacedIndexes.push({ start, end: start + replaced.length });
|
|
||||||
|
|
||||||
return replaced;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const values = await Promise.all(checks);
|
|
||||||
|
|
||||||
for (const check of values) {
|
|
||||||
if (!check.allowed) {
|
|
||||||
input = input.replace(check.after, check.before);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length > limit) {
|
|
||||||
for (const replacedIndex of replacedIndexes) {
|
|
||||||
if (replacedIndex.start < limit && replacedIndex.end >= limit) {
|
|
||||||
return input.substring(0, replacedIndex.end) + '...';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return input.substring(0, limit) + '...';
|
|
||||||
}
|
|
||||||
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getDescription(ticket: Ticket): Promise<string> {
|
|
||||||
return ticket.reason.length <= MAX_DESCRIPTION_LENGTH ? await getLinks(ticket.reason) : await getLinks(ticket.reason, MAX_DESCRIPTION_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAuthor(ticket: Ticket): EmbedAuthorOptions {
|
|
||||||
return {
|
|
||||||
url: `${config.E621_BASE_URL}/users/${ticket.user_id}`,
|
|
||||||
name: ticket.user
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getColor(ticket: Ticket): number {
|
|
||||||
if (!ticket.claimant) {
|
|
||||||
return 0xff0000;
|
|
||||||
} else {
|
|
||||||
return 0x00ffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFields(ticket: Ticket): APIEmbedField[] {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: 'Type',
|
|
||||||
value: ticket.category,
|
|
||||||
inline: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Status',
|
|
||||||
value: ticket.status,
|
|
||||||
inline: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Claimed By',
|
|
||||||
value: !ticket.claimant ? '<Unclaimed>' : ticket.claimant,
|
|
||||||
inline: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createEmbedFromTicket(ticket: Ticket): Promise<EmbedBuilder> {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setTitle(getTitle(ticket))
|
|
||||||
.setURL(getURL(ticket))
|
|
||||||
.setDescription(await getDescription(ticket))
|
|
||||||
.setAuthor(getAuthor(ticket))
|
|
||||||
.setColor(getColor(ticket))
|
|
||||||
.setFields(...getFields(ticket));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function postTicket(data: TicketUpdate) {
|
|
||||||
const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!);
|
|
||||||
|
|
||||||
if (!guildSettings || !guildSettings.tickets_channel_id) return;
|
|
||||||
|
|
||||||
const channel = await discordClient.channels.fetch(guildSettings.tickets_channel_id);
|
|
||||||
|
|
||||||
if (!channel || !channel.isSendable()) return;
|
|
||||||
|
|
||||||
const ticket = data.ticket;
|
|
||||||
|
|
||||||
const embed = await createEmbedFromTicket(ticket);
|
|
||||||
|
|
||||||
const message = await channel.send({ embeds: [embed] });
|
|
||||||
|
|
||||||
await Database.putTicket(ticket.id, message.id);
|
|
||||||
|
|
||||||
sendTicketAlerts(ticket, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateTicket(data: TicketUpdate) {
|
|
||||||
const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!);
|
|
||||||
|
|
||||||
if (!guildSettings || !guildSettings.tickets_channel_id) return;
|
|
||||||
|
|
||||||
const channel = await discordClient.channels.fetch(guildSettings.tickets_channel_id);
|
|
||||||
|
|
||||||
if (!channel || !channel.isSendable()) return;
|
|
||||||
|
|
||||||
const messageId = await Database.getTicketMessageId(data.ticket.id);
|
|
||||||
|
|
||||||
if (!messageId) return postTicket(data);
|
|
||||||
|
|
||||||
const message = await channel.messages.fetch(messageId);
|
|
||||||
const embed = await createEmbedFromTicket(data.ticket);
|
|
||||||
|
|
||||||
if (!message || message.author.id != config.DISCORD_CLIENT_ID) {
|
|
||||||
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] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendTicketAlerts(ticket: Ticket, channel: SendableChannels) {
|
|
||||||
const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!);
|
|
||||||
|
|
||||||
if (!guildSettings || !guildSettings.admin_role_id) return;
|
|
||||||
|
|
||||||
const usersToMention: string[] = [];
|
|
||||||
const rolesToMention: string[] = [];
|
|
||||||
let content = '';
|
|
||||||
|
|
||||||
await Database.getAllTicketPhrases((ticketPhrase: TicketPhrase) => {
|
|
||||||
const { alert, match } = shouldAlert(ticketPhrase, ticket);
|
|
||||||
if (alert) {
|
|
||||||
const mention = ticketPhrase.user_id == 'admin' ? `<@&${guildSettings.admin_role_id!}>` : `<@${ticketPhrase.user_id}>`;
|
|
||||||
|
|
||||||
if (ticketPhrase.user_id == 'admin' && !rolesToMention.includes(guildSettings.admin_role_id!)) {
|
|
||||||
rolesToMention.push(guildSettings.admin_role_id!);
|
|
||||||
} else if (!usersToMention.includes(ticketPhrase.user_id)) {
|
|
||||||
usersToMention.push(ticketPhrase.user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
content += `${mention}: ${match}\n`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (content.length == 0) return;
|
|
||||||
|
|
||||||
await channel.send({
|
|
||||||
content,
|
|
||||||
allowedMentions: {
|
|
||||||
users: usersToMention,
|
|
||||||
roles: rolesToMention
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Client } from 'discord.js';
|
||||||
|
import { BanUpdate } from '../types';
|
||||||
|
import { Database } from '../shared/Database';
|
||||||
|
import { config } from '../config';
|
||||||
|
|
||||||
|
export async function banUpdateHandler(client: Client, update: string) {
|
||||||
|
const data: BanUpdate = JSON.parse(update);
|
||||||
|
|
||||||
|
if (data.action == 'create') {
|
||||||
|
kickDiscordAccounts(client, data);
|
||||||
|
}
|
||||||
|
// else if (data.action == 'delete') {
|
||||||
|
// // unbanDiscordAccounts(data);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function kickDiscordAccounts(client: Client, data: BanUpdate) {
|
||||||
|
const guild = await client.guilds.fetch(config.DISCORD_GUILD_ID!);
|
||||||
|
|
||||||
|
const discordIds = await Database.getDiscordIds(data.ban.user_id);
|
||||||
|
|
||||||
|
for (const id of discordIds) {
|
||||||
|
const member = await guild.members.fetch(id);
|
||||||
|
|
||||||
|
if (member) await member.kick(`Banned from e621 by: https://e621.net/users/${data.ban.banner_id}. Reason:\n${data.ban.reason}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// async function banDiscordAccounts(data: BanUpdate) {
|
||||||
|
// const guild = await discordClient.guilds.fetch(config.DISCORD_GUILD_ID!);
|
||||||
|
|
||||||
|
// const discordIds = await Database.getDiscordIds(data.ban.user_id);
|
||||||
|
|
||||||
|
// for (const id of discordIds) {
|
||||||
|
// await guild.bans.create(id, {
|
||||||
|
// reason: data.ban.reason
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async function unbanDiscordAccounts(data: BanUpdate) {
|
||||||
|
// const guild = await discordClient.guilds.fetch(config.DISCORD_GUILD_ID!);
|
||||||
|
|
||||||
|
// const discordIds = await Database.getDiscordIds(data.ban.user_id);
|
||||||
|
|
||||||
|
// for (const id of discordIds) {
|
||||||
|
// await guild.bans.remove(id);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './alt-utils';
|
export * from './alt-utils';
|
||||||
export * from './array-utils';
|
export * from './array-utils';
|
||||||
export * from './audit-log-utils';
|
export * from './audit-log-utils';
|
||||||
|
export * from './ban-events';
|
||||||
export * from './ban-utils';
|
export * from './ban-utils';
|
||||||
export * from './channel-utils';
|
export * from './channel-utils';
|
||||||
export * from './commands';
|
export * from './commands';
|
||||||
@@ -15,6 +16,7 @@ export * from './record-utils';
|
|||||||
export * from './refresh-commands';
|
export * from './refresh-commands';
|
||||||
export * from './search-regex';
|
export * from './search-regex';
|
||||||
export * from './string-utils';
|
export * from './string-utils';
|
||||||
|
export * from './ticket-events';
|
||||||
export * from './ticket-utils';
|
export * from './ticket-utils';
|
||||||
export * from './wait';
|
export * from './wait';
|
||||||
export * from './whois';
|
export * from './whois';
|
||||||
|
|||||||
@@ -0,0 +1,289 @@
|
|||||||
|
import { Client, EmbedAuthorOptions, APIEmbedField, EmbedBuilder, SendableChannels } from 'discord.js';
|
||||||
|
import { config } from '../config';
|
||||||
|
import { Database } from '../shared/Database';
|
||||||
|
import { TicketUpdate, Ticket, TicketPhrase } from '../types';
|
||||||
|
import { humanizeCapitalization } from './string-utils';
|
||||||
|
import { shouldAlert } from './ticket-utils';
|
||||||
|
import { blipIDRegex, commentIDRegex, forumTopicIDRegex, poolIDRegex, postIDRegex, recordIDRegex, searchLinkRegex, setIDRegex, takedownIDRegex, ticketIDRegex, userIDRegex, wikiLinkRegex } from './search-regex';
|
||||||
|
import { getE621Post, spoilerOrBlacklist, PostAction } from './e621-utils';
|
||||||
|
|
||||||
|
// TODO: Condense this and the message event handler regex array.
|
||||||
|
const linkReplacers = [
|
||||||
|
{
|
||||||
|
regex: blipIDRegex,
|
||||||
|
replacement: '/blips/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: commentIDRegex,
|
||||||
|
replacement: '/comments/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: forumTopicIDRegex,
|
||||||
|
replacement: '/forum_topics/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: poolIDRegex,
|
||||||
|
replacement: '/pools/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: postIDRegex,
|
||||||
|
tester: async (postId: string, before: string, after: string) => {
|
||||||
|
const post = await getE621Post(postId);
|
||||||
|
if (!post) return { allowed: true, before, after };
|
||||||
|
const allowed = spoilerOrBlacklist(post).action != PostAction.Blacklist;
|
||||||
|
|
||||||
|
return { allowed, before, after };
|
||||||
|
},
|
||||||
|
replacement: '/posts/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: recordIDRegex,
|
||||||
|
replacement: '/user_feedbacks/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: searchLinkRegex,
|
||||||
|
replacement: '/posts?tags={match}',
|
||||||
|
encodeURI: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: setIDRegex,
|
||||||
|
replacement: '/post_sets/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: takedownIDRegex,
|
||||||
|
replacement: '/takedowns/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: ticketIDRegex,
|
||||||
|
replacement: '/tickets/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: userIDRegex,
|
||||||
|
replacement: '/users/{match}',
|
||||||
|
encodeURI: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
regex: wikiLinkRegex,
|
||||||
|
replacement: '/wiki_pages/{match}',
|
||||||
|
encodeURI: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const MAX_DESCRIPTION_LENGTH = 500;
|
||||||
|
|
||||||
|
export async function ticketUpdateHandler(client: Client, update: string) {
|
||||||
|
const data: TicketUpdate = JSON.parse(update);
|
||||||
|
|
||||||
|
if (data.action == 'create') {
|
||||||
|
postTicket(client, data);
|
||||||
|
} else {
|
||||||
|
updateTicket(client, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postTicket(client: Client, data: TicketUpdate) {
|
||||||
|
const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!);
|
||||||
|
|
||||||
|
if (!guildSettings || !guildSettings.tickets_channel_id) return;
|
||||||
|
|
||||||
|
const channel = await client.channels.fetch(guildSettings.tickets_channel_id);
|
||||||
|
|
||||||
|
if (!channel || !channel.isSendable()) return;
|
||||||
|
|
||||||
|
const ticket = data.ticket;
|
||||||
|
|
||||||
|
const embed = await createEmbedFromTicket(ticket);
|
||||||
|
|
||||||
|
const message = await channel.send({ embeds: [embed] });
|
||||||
|
|
||||||
|
await Database.putTicket(ticket.id, message.id);
|
||||||
|
|
||||||
|
sendTicketAlerts(ticket, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateTicket(client: Client, data: TicketUpdate) {
|
||||||
|
const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!);
|
||||||
|
|
||||||
|
if (!guildSettings || !guildSettings.tickets_channel_id) return;
|
||||||
|
|
||||||
|
const channel = await client.channels.fetch(guildSettings.tickets_channel_id);
|
||||||
|
|
||||||
|
if (!channel || !channel.isSendable()) return;
|
||||||
|
|
||||||
|
const messageId = await Database.getTicketMessageId(data.ticket.id);
|
||||||
|
|
||||||
|
if (!messageId) return postTicket(client, data);
|
||||||
|
|
||||||
|
const message = await channel.messages.fetch(messageId);
|
||||||
|
const embed = await createEmbedFromTicket(data.ticket);
|
||||||
|
|
||||||
|
if (!message || message.author.id != config.DISCORD_CLIENT_ID) {
|
||||||
|
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 {
|
||||||
|
if (!ticket.target) return `${humanizeCapitalization(ticket.category)} report by ${ticket.user}`;
|
||||||
|
|
||||||
|
switch (ticket.category) {
|
||||||
|
case 'blip':
|
||||||
|
return `Blip by ${ticket.target}`;
|
||||||
|
case 'comment':
|
||||||
|
return `Comment by ${ticket.target}`;
|
||||||
|
case 'dmail':
|
||||||
|
return `DMail sent by ${ticket.target}`;
|
||||||
|
case 'forum':
|
||||||
|
return `Forum post by ${ticket.target}`;
|
||||||
|
case 'pool':
|
||||||
|
return `Pool ${ticket.target}`;
|
||||||
|
case 'post':
|
||||||
|
return `Post uploaded by ${ticket.target}`;
|
||||||
|
case 'set':
|
||||||
|
return `Wow, a rare set report! ${ticket.target}`;
|
||||||
|
case 'user':
|
||||||
|
return `User ${ticket.target}`;
|
||||||
|
case 'wiki':
|
||||||
|
return `Wiki page ${ticket.target}`;
|
||||||
|
default:
|
||||||
|
return 'Uknown ticket category';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getURL(ticket: Ticket): string {
|
||||||
|
return `${config.E621_BASE_URL}/tickets/${ticket.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLinks(input: string, limit: number = Number.MAX_SAFE_INTEGER): Promise<string> {
|
||||||
|
const length = input.length;
|
||||||
|
|
||||||
|
const replacedIndexes: { start: number, end: number }[] = [];
|
||||||
|
const checks: Promise<{ allowed: boolean, before: string, after: string }>[] = [];
|
||||||
|
|
||||||
|
for (const replacer of linkReplacers) {
|
||||||
|
input = input.replaceAll(replacer.regex, (match, group1) => {
|
||||||
|
const replaced = `[${match}](${config.E621_BASE_URL}${(replacer.replacement).replace('{match}', replacer.encodeURI ? encodeURIComponent(group1) : group1)})`;
|
||||||
|
if (replacer.tester) checks.push(replacer.tester(group1, match, replaced));
|
||||||
|
const start = input.indexOf(match);
|
||||||
|
replacedIndexes.push({ start, end: start + replaced.length });
|
||||||
|
|
||||||
|
return replaced;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const values = await Promise.all(checks);
|
||||||
|
|
||||||
|
for (const check of values) {
|
||||||
|
if (!check.allowed) {
|
||||||
|
input = input.replace(check.after, check.before);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > limit) {
|
||||||
|
for (const replacedIndex of replacedIndexes) {
|
||||||
|
if (replacedIndex.start < limit && replacedIndex.end >= limit) {
|
||||||
|
return input.substring(0, replacedIndex.end) + '...';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.substring(0, limit) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDescription(ticket: Ticket): Promise<string> {
|
||||||
|
return ticket.reason.length <= MAX_DESCRIPTION_LENGTH ? await getLinks(ticket.reason) : await getLinks(ticket.reason, MAX_DESCRIPTION_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAuthor(ticket: Ticket): EmbedAuthorOptions {
|
||||||
|
return {
|
||||||
|
url: `${config.E621_BASE_URL}/users/${ticket.user_id}`,
|
||||||
|
name: ticket.user
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColor(ticket: Ticket): number {
|
||||||
|
if (!ticket.claimant) {
|
||||||
|
return 0xff0000;
|
||||||
|
} else {
|
||||||
|
return 0x00ffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFields(ticket: Ticket): APIEmbedField[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'Type',
|
||||||
|
value: ticket.category,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Status',
|
||||||
|
value: ticket.status,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Claimed By',
|
||||||
|
value: !ticket.claimant ? '<Unclaimed>' : ticket.claimant,
|
||||||
|
inline: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createEmbedFromTicket(ticket: Ticket): Promise<EmbedBuilder> {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(getTitle(ticket))
|
||||||
|
.setURL(getURL(ticket))
|
||||||
|
.setDescription(await getDescription(ticket))
|
||||||
|
.setAuthor(getAuthor(ticket))
|
||||||
|
.setColor(getColor(ticket))
|
||||||
|
.setFields(...getFields(ticket));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendTicketAlerts(ticket: Ticket, channel: SendableChannels) {
|
||||||
|
const guildSettings = await Database.getGuildSettings(config.DISCORD_GUILD_ID!);
|
||||||
|
|
||||||
|
if (!guildSettings || !guildSettings.admin_role_id) return;
|
||||||
|
|
||||||
|
const usersToMention: string[] = [];
|
||||||
|
const rolesToMention: string[] = [];
|
||||||
|
let content = '';
|
||||||
|
|
||||||
|
await Database.getAllTicketPhrases((ticketPhrase: TicketPhrase) => {
|
||||||
|
const { alert, match } = shouldAlert(ticketPhrase, ticket);
|
||||||
|
if (alert) {
|
||||||
|
const mention = ticketPhrase.user_id == 'admin' ? `<@&${guildSettings.admin_role_id!}>` : `<@${ticketPhrase.user_id}>`;
|
||||||
|
|
||||||
|
if (ticketPhrase.user_id == 'admin' && !rolesToMention.includes(guildSettings.admin_role_id!)) {
|
||||||
|
rolesToMention.push(guildSettings.admin_role_id!);
|
||||||
|
} else if (!usersToMention.includes(ticketPhrase.user_id)) {
|
||||||
|
usersToMention.push(ticketPhrase.user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
content += `${mention}: ${match}\n`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (content.length == 0) return;
|
||||||
|
|
||||||
|
await channel.send({
|
||||||
|
content,
|
||||||
|
allowedMentions: {
|
||||||
|
users: usersToMention,
|
||||||
|
roles: rolesToMention
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user