Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/commands/Core/help.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {
import {
SlashCommandBuilder,
ActionRowBuilder,
ButtonBuilder,
Expand Down Expand Up @@ -44,7 +44,7 @@ const CATEGORY_ICONS = {



async function createInitialHelpMenu() {
async function createInitialHelpMenu(client) {
const commandsPath = path.join(__dirname, "../../commands");
const categoryDirs = (
await fs.readdir(commandsPath, { withFileTypes: true })
Expand Down Expand Up @@ -72,8 +72,9 @@ async function createInitialHelpMenu() {
}),
];

const botName = client?.user?.username || "Bot";
const embed = createEmbed({
title: "🤖 TitanBot Help Center",
title: `🤖 ${botName} Help Center`,
description: "Your all-in-one Discord companion for moderation, economy, fun, and server management.",
color: 'primary'
});
Expand Down Expand Up @@ -204,7 +205,7 @@ export default {
const { MessageFlags } = await import('discord.js');
await InteractionHelper.safeDefer(interaction);

const { embeds, components } = await createInitialHelpMenu();
const { embeds, components } = await createInitialHelpMenu(client);

await InteractionHelper.safeEditReply(interaction, {
embeds,
Expand Down
16 changes: 2 additions & 14 deletions src/commands/Ticket/claim.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { getColor } from '../../config/bot.js';
import { SlashCommandBuilder, PermissionFlagsBits, PermissionsBitField, ChannelType, MessageFlags } from 'discord.js';
import { createEmbed, errorEmbed, successEmbed, infoEmbed, warningEmbed } from '../../utils/embeds.js';
import { claimTicket } from '../../services/ticket.js';
import { logEvent } from '../../utils/moderation.js';
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags } from 'discord.js';
import { errorEmbed, successEmbed } from '../../utils/embeds.js';
import { logger } from '../../utils/logger.js';
import { handleInteractionError } from '../../utils/errorHandler.js';
import { InteractionHelper } from '../../utils/interactionHelper.js';
Expand Down Expand Up @@ -82,16 +80,6 @@ export default {
commandName: 'claim'
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: "Ticket Claimed",
target: channel.toString(),
executor: interaction.user.toString()
}
});

} catch (error) {
logger.error('Error executing claim command', {
error: error.message,
Expand Down
17 changes: 2 additions & 15 deletions src/commands/Ticket/close.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { getColor } from '../../config/bot.js';
import { SlashCommandBuilder, PermissionFlagsBits, PermissionsBitField, ChannelType, MessageFlags } from 'discord.js';
import { createEmbed, errorEmbed, successEmbed, infoEmbed, warningEmbed } from '../../utils/embeds.js';
import { closeTicket } from '../../services/ticket.js';
import { logEvent } from '../../utils/moderation.js';
import { SlashCommandBuilder, PermissionFlagsBits, ChannelType, MessageFlags } from 'discord.js';
import { errorEmbed, successEmbed } from '../../utils/embeds.js';
import { logger } from '../../utils/logger.js';
import { handleInteractionError } from '../../utils/errorHandler.js';
import { InteractionHelper } from '../../utils/interactionHelper.js';
Expand Down Expand Up @@ -93,17 +91,6 @@ export default {
commandName: 'close'
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: "Ticket Closed",
target: channel.toString(),
executor: interaction.user.toString(),
reason: reason
}
});

} catch (error) {
logger.error('Error executing close command', {
error: error.message,
Expand Down
17 changes: 2 additions & 15 deletions src/commands/Ticket/priority.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { getColor } from '../../config/bot.js';
import { SlashCommandBuilder, PermissionFlagsBits, PermissionsBitField, ChannelType, MessageFlags } from 'discord.js';
import { createEmbed, errorEmbed, successEmbed, infoEmbed, warningEmbed } from '../../utils/embeds.js';
import { updateTicketPriority } from '../../services/ticket.js';
import { logEvent } from '../../utils/moderation.js';
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags } from 'discord.js';
import { errorEmbed, successEmbed } from '../../utils/embeds.js';
import { logger } from '../../utils/logger.js';
import { handleInteractionError } from '../../utils/errorHandler.js';
import { InteractionHelper } from '../../utils/interactionHelper.js';
Expand Down Expand Up @@ -98,17 +96,6 @@ export default {
commandName: 'priority'
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: "Priority Updated",
target: interaction.channel.toString(),
executor: interaction.user.toString(),
reason: `Priority set to ${priorityLevel.toUpperCase()}`
}
});

} catch (error) {
logger.error('Error executing priority command', {
error: error.message,
Expand Down
12 changes: 1 addition & 11 deletions src/commands/Ticket/ticket.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { getColor } from '../../config/bot.js';
import { SlashCommandBuilder, PermissionFlagsBits, PermissionsBitField, ChannelType, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags } from 'discord.js';
import { createEmbed, errorEmbed, successEmbed, infoEmbed, warningEmbed } from '../../utils/embeds.js';
import { getGuildConfig } from '../../services/guildConfig.js';
import { logEvent } from '../../utils/moderation.js';
import { InteractionHelper } from '../../utils/interactionHelper.js';
import { logger } from '../../utils/logger.js';
import { handleInteractionError } from '../../utils/errorHandler.js';
Expand Down Expand Up @@ -286,16 +285,7 @@ description: panelMessage,
},
);

logEvent({
client,
guildId: interaction.guildId,
event: {
action: "Ticket System Setup",
target: panelChannel.toString(),
executor: interaction.user.toString(),
reason: "Ticket panel configuration"
}
});

} catch (error) {
logger.error('Ticket setup error', {
error: error.message,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/Welcome/goodbye.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default {
const ping = options.getBoolean('ping') ?? false;

const existingConfig = await getWelcomeConfig(client, guild.id);
if (hasGoodbyeSetup(existingConfig)) {
if (existingConfig?.goodbyeChannelId) {
logger.info(`[Goodbye] Setup blocked because config already exists in channel ${existingConfig.goodbyeChannelId} for guild ${guild.id}`);
return await InteractionHelper.safeEditReply(interaction, {
embeds: [errorEmbed(
Expand Down
2 changes: 1 addition & 1 deletion src/commands/Welcome/welcome.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default {
const ping = options.getBoolean('ping') ?? false;

const existingConfig = await getWelcomeConfig(client, guild.id);
if (hasWelcomeSetup(existingConfig)) {
if (existingConfig?.channelId) {
logger.info(`[Welcome] Setup blocked because config already exists in channel ${existingConfig.channelId} for guild ${guild.id}`);
return await InteractionHelper.safeEditReply(interaction, {
embeds: [errorEmbed(
Expand Down
53 changes: 6 additions & 47 deletions src/handlers/ticketButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, Attac
import { createEmbed, errorEmbed, successEmbed } from '../utils/embeds.js';
import { createTicket, closeTicket, claimTicket, updateTicketPriority } from '../services/ticket.js';
import { getGuildConfig } from '../services/guildConfig.js';
import { logEvent } from '../utils/moderation.js';
import { logTicketEvent } from '../utils/ticketLogging.js';
import { logger } from '../utils/logger.js';
import { InteractionHelper } from '../utils/interactionHelper.js';
Expand Down Expand Up @@ -352,16 +351,6 @@ const claimTicketHandler = {
embeds: [successEmbed('Ticket Claimed', 'You have successfully claimed this ticket!')],
flags: MessageFlags.Ephemeral
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: 'Ticket Claimed',
target: interaction.channel.toString(),
executor: interaction.user.toString()
}
});
} else {
await interaction.editReply({
embeds: [errorEmbed('Error', result.error || 'Failed to claim ticket.')],
Expand Down Expand Up @@ -490,19 +479,19 @@ const pinTicketHandler = {
}

// Check if channel name already has ping emoji
const hasPingEmoji = channel.name.startsWith('📍');
const hasPingEmoji = channel.name.startsWith('📌');

if (hasPingEmoji) {
// Unpin: remove emoji and update position
const newName = channel.name.replace(/^📍\s*/, '');
const newName = channel.name.replace(/^📌\s*/, '');
await channel.edit({
name: newName,
position: 999 // Move to end
});

await interaction.editReply({
embeds: [createEmbed({
title: '📍 Ticket Unpinned',
title: '📌 Ticket Unpinned',
description: 'This ticket has been unpinned and moved back to normal position.',
color: 0x95A5A6
})],
Expand All @@ -517,15 +506,15 @@ const pinTicketHandler = {
});
} else {
// Pin: add emoji and update position
const newName = `📍 ${channel.name}`;
const newName = `📌 ${channel.name}`;
await channel.edit({
name: newName,
position: 0 // Move to top
});

await interaction.editReply({
embeds: [createEmbed({
title: '📍 Ticket Pinned',
title: '📌 Ticket Pinned',
description: 'This ticket has been pinned to the top of the category.',
color: 0x3498db
})],
Expand All @@ -551,7 +540,7 @@ const pinTicketHandler = {
executorId: interaction.user.id,
metadata: {
isPinned: !hasPingEmoji,
newChannelName: hasPingEmoji ? channel.name.replace(/^📍\s*/, '') : `📍 ${channel.name}`
newChannelName: hasPingEmoji ? channel.name.replace(/^📌\s*/, '') : `📌 ${channel.name}`
}
}
});
Expand Down Expand Up @@ -608,16 +597,6 @@ const unclaimTicketHandler = {
embeds: [successEmbed('Ticket Unclaimed', 'You have successfully unclaimed this ticket!')],
flags: MessageFlags.Ephemeral
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: 'Ticket Unclaimed',
target: interaction.channel.toString(),
executor: interaction.user.toString()
}
});
} else {
await interaction.editReply({
embeds: [errorEmbed('Error', result.error || 'Failed to unclaim ticket.')],
Expand Down Expand Up @@ -681,16 +660,6 @@ const reopenTicketHandler = {
embeds: [successEmbed('Ticket Reopened', reopenMessage)],
flags: MessageFlags.Ephemeral
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: 'Ticket Reopened',
target: interaction.channel.toString(),
executor: interaction.user.toString()
}
});
} else {
await interaction.editReply({
embeds: [errorEmbed('Error', result.error || 'Failed to reopen ticket.')],
Expand Down Expand Up @@ -750,16 +719,6 @@ const deleteTicketHandler = {
embeds: [successEmbed('Ticket Deleted', 'This ticket will be permanently deleted in 3 seconds.')],
flags: MessageFlags.Ephemeral
});

await logEvent({
client,
guildId: interaction.guildId,
event: {
action: 'Ticket Deleted',
target: interaction.channel.toString(),
executor: interaction.user.toString()
}
});
} else {
await interaction.editReply({
embeds: [errorEmbed('Error', result.error || 'Failed to delete ticket.')],
Expand Down
7 changes: 2 additions & 5 deletions src/services/ticket.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
AttachmentBuilder,
} from 'discord.js';
import { getGuildConfig } from './guildConfig.js';
import { getTicketData, saveTicketData, deleteTicketData, getOpenTicketCountForUser } from '../utils/database.js';
import { getTicketData, saveTicketData, deleteTicketData, getOpenTicketCountForUser, incrementTicketCounter } from '../utils/database.js';
import { logger } from '../utils/logger.js';
import { createEmbed, errorEmbed } from '../utils/embeds.js';
import { logTicketEvent } from '../utils/ticketLogging.js';
Expand Down Expand Up @@ -46,8 +46,6 @@ function getPriorityMap() {
const PRIORITY_MAP = getPriorityMap();
const TICKET_DELETE_DELAY_MS = 3000;
const TICKET_DELETE_DELAY_SECONDS = Math.floor(TICKET_DELETE_DELAY_MS / 1000);
const TICKET_NUMBER_BASE = 100;
const TICKET_NUMBER_RANGE = 900;



Expand Down Expand Up @@ -1134,8 +1132,7 @@ export async function unclaimTicket(channel, unclaimer) {
}

async function getNextTicketNumber(guildId) {
const randomTicket = Math.floor(Math.random() * TICKET_NUMBER_RANGE) + TICKET_NUMBER_BASE;
return randomTicket.toString();
return await incrementTicketCounter(guildId);
}

export async function updateTicketPriority(channel, priority, updater) {
Expand Down
30 changes: 30 additions & 0 deletions src/utils/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,35 @@ export async function deleteTicketData(guildId, channelId) {
await db.delete(key);
}

export function getTicketCounterKey(guildId) {
return `guild:${guildId}:ticket:counter`;
}

export async function getTicketCounter(guildId) {
if (!db.initialized) {
await db.initialize();
}

const key = getTicketCounterKey(guildId);
const counter = await db.get(key);
return counter || 0;
}

export async function incrementTicketCounter(guildId) {
if (!db.initialized) {
await db.initialize();
}

const key = getTicketCounterKey(guildId);
const currentCounter = await getTicketCounter(guildId);
const nextCounter = currentCounter + 1;

await db.set(key, nextCounter);

// Return padded to 3 digits (001, 002, etc.)
return nextCounter.toString().padStart(3, '0');
}




Expand Down Expand Up @@ -745,6 +774,7 @@ function normalizeWelcomeConfig(raw = {}) {
leaveMessage,
leaveEmbed,
dmMessage: base.dmMessage ?? "",
goodbyePing: Boolean(base.goodbyePing),
roleIds,
autoRoleDelay: base.autoRoleDelay ?? 0,
joinLogs: base.joinLogs ?? { enabled: false, channelId: null },
Expand Down
Loading