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
4 changes: 3 additions & 1 deletion src/commands/Giveaway/gend.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ export default {
const winnerMentions = winners
.map((id) => `<@${id}>`)
.join(", ");
await channel.send({
const winnerPingMsg = await channel.send({
content: `🎉 CONGRATULATIONS ${winnerMentions}! You won the **${updatedGiveaway.prize}** giveaway! Please contact the host <@${updatedGiveaway.hostId}> to claim your prize.`,
});
updatedGiveaway.winnerPingMessageId = winnerPingMsg.id;
await saveGiveaway(interaction.client, interaction.guildId, updatedGiveaway);

logger.info(`Giveaway ended with ${winners.length} winner(s): ${messageId}`);

Expand Down
34 changes: 28 additions & 6 deletions src/commands/Giveaway/greroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,20 @@ export default {
.map((id) => `<@${id}>`)
.join(", ");

await channel.send({
content: `🔄 **GIVEAWAY REROLL** 🔄 New winners for **${giveaway.prize}**: ${winnerMentions}!`,
});
// Edit the original winner ping if it still exists, otherwise send a new one
const existingPingMsg = giveaway.winnerPingMessageId
? await channel.messages.fetch(giveaway.winnerPingMessageId).catch(() => null)
: null;
if (existingPingMsg) {
await existingPingMsg.edit({
content: `🔄 **GIVEAWAY REROLL** 🔄 New winners for **${giveaway.prize}**: ${winnerMentions}!`,
});
} else {
const newPingMsg = await channel.send({
content: `🔄 **GIVEAWAY REROLL** 🔄 New winners for **${giveaway.prize}**: ${winnerMentions}!`,
});
updatedGiveaway.winnerPingMessageId = newPingMsg.id;
}

logger.info(`Giveaway rerolled (message not found, but announced): ${messageId}`);

Expand Down Expand Up @@ -229,9 +240,20 @@ export default {
.map((id) => `<@${id}>`)
.join(", ");

await channel.send({
content: `🔄 **REROLL WINNERS** 🔄 CONGRATULATIONS ${winnerMentions}! You are the new winner(s) for the **${giveaway.prize}** giveaway! Please contact the host <@${giveaway.hostId}> to claim your prize.`,
});
// Edit the original winner ping if it still exists, otherwise send a new one
const existingPingMsg = giveaway.winnerPingMessageId
? await channel.messages.fetch(giveaway.winnerPingMessageId).catch(() => null)
: null;
if (existingPingMsg) {
await existingPingMsg.edit({
content: `🔄 **REROLL WINNERS** 🔄 CONGRATULATIONS ${winnerMentions}! You are the new winner(s) for the **${giveaway.prize}** giveaway! Please contact the host <@${giveaway.hostId}> to claim your prize.`,
});
} else {
const newPingMsg = await channel.send({
content: `🔄 **REROLL WINNERS** 🔄 CONGRATULATIONS ${winnerMentions}! You are the new winner(s) for the **${giveaway.prize}** giveaway! Please contact the host <@${giveaway.hostId}> to claim your prize.`,
});
updatedGiveaway.winnerPingMessageId = newPingMsg.id;
}

logger.info(`Giveaway successfully rerolled: ${messageId} with ${newWinners.length} new winners`);

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
4 changes: 3 additions & 1 deletion src/services/giveawayService.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,9 @@ export async function checkGiveaways(client) {

if (winners.length > 0) {
const winnerAnnouncement = `🎉 Congratulations ${winnerMentions}! You won the **${giveaway.prize || 'giveaway'}**! Please contact <@${giveaway.hostId}> to claim your prize.`;
await channel.send({ content: winnerAnnouncement });
const winnerPingMsg = await channel.send({ content: winnerAnnouncement });
giveaway.winnerPingMessageId = winnerPingMsg.id;
await markGiveawayEnded(client, giveawayId, giveaway);


try {
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
Loading
Loading