Change private help ticket cooldown
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags, ChannelType, PermissionFlagsBits, ButtonBuilder, ButtonStyle } from 'discord.js';
|
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags, ChannelType, PermissionFlagsBits, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -19,7 +18,7 @@ export default {
|
|||||||
const guildSettings = await Database.getGuildSettings(guild.id);
|
const guildSettings = await Database.getGuildSettings(guild.id);
|
||||||
|
|
||||||
if (!guildSettings || !guildSettings.private_help_role_id)
|
if (!guildSettings || !guildSettings.private_help_role_id)
|
||||||
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Failed to create ticket.' });
|
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Failed to claim ticket.' });
|
||||||
|
|
||||||
const closeButton = new ButtonBuilder()
|
const closeButton = new ButtonBuilder()
|
||||||
.setCustomId('close-ticket')
|
.setCustomId('close-ticket')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags, ChannelType, ButtonBuilder, ButtonStyle } from 'discord.js';
|
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags, ChannelType, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
import { Database } from '../shared/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'close-ticket',
|
name: 'close-ticket',
|
||||||
@@ -14,6 +14,8 @@ export default {
|
|||||||
components: []
|
components: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Database.closePrivateHelpTicket(channel.id);
|
||||||
|
|
||||||
await channel.send(`This ticket has been closed by ${interaction.user}`);
|
await channel.send(`This ticket has been closed by ${interaction.user}`);
|
||||||
|
|
||||||
await interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Ticket closed.' });
|
await interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Ticket closed.' });
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags } from 'discord.js';
|
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags } from 'discord.js';
|
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
import { canOpenPrivateHelpTicket } from '../utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'private-help',
|
name: 'private-help',
|
||||||
handler: async function (client: Client, interaction: ButtonInteraction) {
|
handler: async function (client: Client, interaction: ButtonInteraction) {
|
||||||
const allowedAt = ticketCooldownMap.get(interaction.user.id);
|
if (!(await canOpenPrivateHelpTicket(interaction.user.id)))
|
||||||
|
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'You can only have one open ticket at a time that is less than a day old.' });
|
||||||
if (allowedAt && Date.now() < allowedAt)
|
|
||||||
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'You can only create one ticket per day.' });
|
|
||||||
|
|
||||||
const modal = new ModalBuilder()
|
const modal = new ModalBuilder()
|
||||||
.setCustomId('open-ticket-modal')
|
.setCustomId('open-ticket-modal')
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags, ChannelType, PermissionFlagsBits, ButtonBuilder, ButtonStyle } from 'discord.js';
|
import { ActionRowBuilder, ButtonInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle, MessageFlags, ChannelType, PermissionFlagsBits, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -21,7 +20,7 @@ export default {
|
|||||||
const guildSettings = await Database.getGuildSettings(guild.id);
|
const guildSettings = await Database.getGuildSettings(guild.id);
|
||||||
|
|
||||||
if (!guildSettings || !guildSettings.private_help_role_id)
|
if (!guildSettings || !guildSettings.private_help_role_id)
|
||||||
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Failed to create ticket.' });
|
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Failed to unclaim ticket.' });
|
||||||
|
|
||||||
const closeButton = new ButtonBuilder()
|
const closeButton = new ButtonBuilder()
|
||||||
.setCustomId('close-ticket')
|
.setCustomId('close-ticket')
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { checkExpiredBans, initIfNecessary, loadHandlersFrom, refreshCommands }
|
|||||||
import { initializeWebserver } from './webserver';
|
import { initializeWebserver } from './webserver';
|
||||||
import { Database } from './shared/Database';
|
import { Database } from './shared/Database';
|
||||||
import { handleAuditLogCreate, handleBanRemove, handleBulkMessageDelete, handleGuildCreate, handleMemberJoin, handleMessageCreate, handleMessageDelete, handleMessageUpdate, handleThreadCreate, handleVoiceStateUpdate } from './events';
|
import { handleAuditLogCreate, handleBanRemove, handleBulkMessageDelete, handleGuildCreate, handleMemberJoin, handleMessageCreate, handleMessageDelete, handleMessageUpdate, handleThreadCreate, handleVoiceStateUpdate } from './events';
|
||||||
import { pruneOldTickets, ticketCooldownMap } from './shared/ticket-cooldown';
|
|
||||||
import { openRedisClient } from './shared/RedisClient';
|
import { openRedisClient } from './shared/RedisClient';
|
||||||
|
|
||||||
let ready = false;
|
let ready = false;
|
||||||
@@ -137,9 +136,6 @@ client.on('ready', async () => {
|
|||||||
|
|
||||||
await initializeWebserver(client);
|
await initializeWebserver(client);
|
||||||
|
|
||||||
// Prune ticket cooldowns that are expired every day
|
|
||||||
setInterval(pruneOldTickets, 8.64e+7);
|
|
||||||
|
|
||||||
// Check for expired bans every 5 minutes
|
// Check for expired bans every 5 minutes
|
||||||
checkExpiredBans(client);
|
checkExpiredBans(client);
|
||||||
setInterval(checkExpiredBans.bind(null, client), 300000);
|
setInterval(checkExpiredBans.bind(null, client), 300000);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, GuildTextBasedChannel, MessageFlags, ModalSubmitInteraction, TextChannel, ThreadAutoArchiveDuration } from 'discord.js';
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, GuildTextBasedChannel, MessageFlags, ModalSubmitInteraction, TextChannel, ThreadAutoArchiveDuration } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
import { logCustomEvent } from '../utils';
|
import { logCustomEvent } from '../utils';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, GuildTextBasedChannel, MessageFlags, ModalSubmitInteraction, TextChannel, ThreadAutoArchiveDuration } from 'discord.js';
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, GuildTextBasedChannel, MessageFlags, ModalSubmitInteraction, TextChannel, ThreadAutoArchiveDuration } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -13,8 +12,6 @@ export default {
|
|||||||
if (!guildSettings || !guildSettings.private_help_role_id)
|
if (!guildSettings || !guildSettings.private_help_role_id)
|
||||||
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Failed to create ticket. Please report this to a staff member.' });
|
return interaction.reply({ flags: [MessageFlags.Ephemeral], content: 'Failed to create ticket. Please report this to a staff member.' });
|
||||||
|
|
||||||
ticketCooldownMap.set(interaction.user.id, Date.now() + 8.64e+7);
|
|
||||||
|
|
||||||
const reason = interaction.fields.getTextInputValue('ticket-message');
|
const reason = interaction.fields.getTextInputValue('ticket-message');
|
||||||
|
|
||||||
const channel = (await interaction.channel?.fetch()) as TextChannel;
|
const channel = (await interaction.channel?.fetch()) as TextChannel;
|
||||||
@@ -26,6 +23,12 @@ export default {
|
|||||||
type: ChannelType.PrivateThread
|
type: ChannelType.PrivateThread
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
await Database.createPrivateHelpTicket(interaction.user.id, thread.id);
|
||||||
|
|
||||||
|
console.log(2);
|
||||||
|
|
||||||
const closeButton = new ButtonBuilder()
|
const closeButton = new ButtonBuilder()
|
||||||
.setCustomId('close-ticket')
|
.setCustomId('close-ticket')
|
||||||
.setLabel('Click here if you no longer need help')
|
.setLabel('Click here if you no longer need help')
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, GuildTextBasedChannel, MessageFlags, ModalSubmitInteraction, TextChannel, ThreadAutoArchiveDuration } from 'discord.js';
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, Client, GuildTextBasedChannel, MessageFlags, ModalSubmitInteraction, TextChannel, ThreadAutoArchiveDuration } from 'discord.js';
|
||||||
import { ticketCooldownMap } from '../shared/ticket-cooldown';
|
|
||||||
import { Database } from '../shared/Database';
|
import { Database } from '../shared/Database';
|
||||||
import { deferInteraction, logCustomEvent, syncName } from '../utils';
|
import { deferInteraction, logCustomEvent, syncName } from '../utils';
|
||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
|
|||||||
+35
-4
@@ -1,9 +1,7 @@
|
|||||||
import sqlite3 from 'sqlite3';
|
import sqlite3 from 'sqlite3';
|
||||||
import { open, Database as SqliteDatabase } from 'sqlite';
|
import { open, Database as SqliteDatabase } from 'sqlite';
|
||||||
import { config } from '../config';
|
|
||||||
import DiscordOAuth2 from 'discord-oauth2';
|
|
||||||
import { serializeMessage, wait } from '../utils';
|
import { serializeMessage, wait } from '../utils';
|
||||||
import { GuildSettings, LoggedMessage, TicketMessage, TicketPhrase, Note, Ban, GuildArraySetting, GithubUserMapping, KnowledgebaseItem } from '../types';
|
import { GuildSettings, LoggedMessage, TicketMessage, TicketPhrase, Note, Ban, GuildArraySetting, GithubUserMapping, KnowledgebaseItem, PrivateHelpTicket } from '../types';
|
||||||
import { Message } from '../events';
|
import { Message } from '../events';
|
||||||
|
|
||||||
const DB_SCHEMA = `
|
const DB_SCHEMA = `
|
||||||
@@ -67,6 +65,8 @@ const DB_SCHEMA = `
|
|||||||
timestamp datetime NOT NULL DEFAULT (datetime('now', 'localtime'))
|
timestamp datetime NOT NULL DEFAULT (datetime('now', 'localtime'))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS index_user_ids ON notes (user_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS note_edits (
|
CREATE TABLE IF NOT EXISTS note_edits (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
note_id INTEGER,
|
note_id INTEGER,
|
||||||
@@ -93,9 +93,24 @@ const DB_SCHEMA = `
|
|||||||
guild_id TEXT NOT NULL,
|
guild_id TEXT NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
content TEXT NOT NULL
|
content TEXT NOT NULL
|
||||||
)
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS private_help_tickets (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
thread_id TEXT NOT NULL,
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
status INTEGER NOT NULL,
|
||||||
|
timestamp datetime NOT NULL DEFAULT (datetime('now', 'localtime'))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS index_timestamp ON private_help_tickets (timestamp);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const enum PrivateHelpTicketStatus {
|
||||||
|
OPEN = 0,
|
||||||
|
CLOSED = 1
|
||||||
|
}
|
||||||
|
|
||||||
export class Database {
|
export class Database {
|
||||||
private static db: SqliteDatabase;
|
private static db: SqliteDatabase;
|
||||||
|
|
||||||
@@ -434,4 +449,20 @@ export class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -- END KNOWLEDGEBASE --
|
// -- END KNOWLEDGEBASE --
|
||||||
|
|
||||||
|
// -- START PRIVATE HELP TICKETS --
|
||||||
|
|
||||||
|
static async createPrivateHelpTicket(userId: string, threadId: string) {
|
||||||
|
await Database.db.run('INSERT INTO private_help_tickets(user_id, thread_id, status) VALUES (?, ?, ?)', userId, threadId, PrivateHelpTicketStatus.OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async closePrivateHelpTicket(threadId: string) {
|
||||||
|
await Database.db.run('UPDATE private_help_tickets SET status = ? WHERE thread_id = ?', PrivateHelpTicketStatus.CLOSED, threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getLatestPrivateHelpTicketBy(userId: string): Promise<PrivateHelpTicket | undefined> {
|
||||||
|
return await Database.db.get<PrivateHelpTicket>('SELECT * from private_help_tickets WHERE user_id = ? ORDER BY timestamp DESC LIMIT 1', userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- END PRIVATE HELP TICKETS
|
||||||
}
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
export const ticketCooldownMap = new Map<string, number>();
|
|
||||||
|
|
||||||
export function pruneOldTickets() {
|
|
||||||
const keys = Array.from(ticketCooldownMap.keys());
|
|
||||||
for (const key of keys) {
|
|
||||||
if (Date.now() >= ticketCooldownMap.get(key)!)
|
|
||||||
ticketCooldownMap.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
+7
@@ -65,4 +65,11 @@ export type KnowledgebaseItem = {
|
|||||||
guild_id: string
|
guild_id: string
|
||||||
name: string
|
name: string
|
||||||
content: string
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PrivateHelpTicket = {
|
||||||
|
id: number
|
||||||
|
user_id: string
|
||||||
|
status: PrivateHelpTicketStatus,
|
||||||
|
timestamp: string
|
||||||
}
|
}
|
||||||
Vendored
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
export * from './command';
|
export * from './command.d';
|
||||||
export * from './database-types';
|
export * from './database-types.d';
|
||||||
export * from './e621-types';
|
export * from './e621-types.d';
|
||||||
export * from './handler';
|
export * from './handler.d';
|
||||||
export * from './helper-types';
|
export * from './helper-types.d';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Client, Guild, User } from 'discord.js';
|
import { Client, Guild, User } from 'discord.js';
|
||||||
|
import { Database, PrivateHelpTicketStatus } from '../shared/Database';
|
||||||
|
|
||||||
export async function resolveUser(client: Client, value: string, guild: Guild | null = null): Promise<User | null | undefined> {
|
export async function resolveUser(client: Client, value: string, guild: Guild | null = null): Promise<User | null | undefined> {
|
||||||
let user: User | null | undefined = null;
|
let user: User | null | undefined = null;
|
||||||
@@ -24,4 +25,12 @@ export async function resolveUser(client: Client, value: string, guild: Guild |
|
|||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function canOpenPrivateHelpTicket(id: string): Promise<boolean> {
|
||||||
|
const latestTicket = await Database.getLatestPrivateHelpTicketBy(id);
|
||||||
|
|
||||||
|
if (latestTicket && latestTicket.status == PrivateHelpTicketStatus.OPEN && Date.now() - new Date(latestTicket.timestamp).getTime() < 8.64e+7) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user