Skip to content

Commit

Permalink
v0.15.25
Browse files Browse the repository at this point in the history
- Fixed error that sends closed ticket dm to wrong person
- Adding the PanelEMbed config directly in the config.yml file
- Updated database schemas
- Now when you create a ticket it will be stored in the database
- Adding the author ticket and CreateAT ticket in the closed dm notif
  • Loading branch information
LucasB25 committed Jun 6, 2024
1 parent 646c4c9 commit b57ef76
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 28 deletions.
24 changes: 23 additions & 1 deletion config.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,29 @@ ticketCategories:
menuDescription: 'For billing-related inquiries and payment issues.'
# Emoji associated with this category (leave empty if none)
menuEmoji: '💳'

# ================================
# Embed description for this category
embedDescription: 'Welcome to Category 3! Have any questions or issues regarding billing or payments? Let us know.'

# ==============================================
# Embeds Locale
# ==============================================

embeds:
#PanelEMbed
panelEmbed:
color: "#0099FF"
title: "AikouTicket"
description: "To create a support ticket, please select one of the options below based on the assistance you require."
timestamp: true
URL: ""
image: "https://cdn.discordapp.com/attachments/1109764526552915988/1136666715078533303/image.png?ex=6647695f&is=664617df&hm=ec6a3e7de621daf0813e7a70c6ec7b2c9741bad8450172d356f85f28273610b2&"
thumbnail: ""
footer:
text: "AikouTicket"
iconURL: ""
author:
name: ""
iconURL: ""
url: ""
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "AikouTicket",
"version": "0.15.20",
"version": "0.15.25",
"description": "A simple AikouTicket bot for discord",
"type": "module",
"main": "dist/index.js",
Expand Down
Binary file modified prisma/aikouticket.db
Binary file not shown.
9 changes: 8 additions & 1 deletion prisma/example.mongodb.schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ datasource db {
url = env("DATABASE_URL")
}

model tickets {
model ticketsGuild {
guildId String @id @map("_id")
selectMenuOptions String
}

model ticketsInfo {
id String @id @default(cuid()) @map("_id")
channelid String @unique
creator String
createdAt BigInt
}
9 changes: 8 additions & 1 deletion prisma/example.postgresql.schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ datasource db {
url = env("DATABASE_URL")
}

model tickets {
model ticketsGuild {
guildId String @id
selectMenuOptions String
}

model ticketsInfo {
id String @id @default(uuid())
channelid String @unique
creator String
createdAt BigInt
}
9 changes: 8 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ datasource db {
url = "file:./aikouticket.db"
}

model tickets {
model ticketsGuild {
guildId String @id
selectMenuOptions String
}

model ticketsInfo {
id String @id @default(uuid())
channelid String @unique
creator String
createdAt BigInt
}
18 changes: 7 additions & 11 deletions src/commands/tickets/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export default class PanelCommand extends Command {
await ctx.sendDeferMessage({ ephemeral: true });
const config = await TicketManager.readConfigFile();

const panelEmbed = this.createPanelEmbed(client);
const panelEmbedConfig = config.embeds.panelEmbed;
const panelEmbed = this.createPanelEmbed(client, panelEmbedConfig);

const selectMenu = this.createSelectMenu(config.ticketCategories, config.menuPlaceholder);

const actionRowsMenus = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu);
Expand All @@ -51,16 +53,10 @@ export default class PanelCommand extends Command {
}
}

createPanelEmbed(client: Bot): EmbedBuilder {
return client
.embed()
.setColor(this.client.color)
.setTitle('AikouTicket')
.setDescription('To create a support ticket, please select one of the options below based on the assistance you require.')
.setImage(
'https://cdn.discordapp.com/attachments/1109764526552915988/1136666715078533303/image.png?ex=6647695f&is=664617df&hm=ec6a3e7de621daf0813e7a70c6ec7b2c9741bad8450172d356f85f28273610b2&',
)
.setTimestamp();
createPanelEmbed(_client: Bot, panelEmbedConfig: any): EmbedBuilder {
const embed = TicketManager.buildEmbed(panelEmbedConfig);

return embed;
}

createSelectMenu(ticketCategories: any, placeholder: string): StringSelectMenuBuilder {
Expand Down
52 changes: 47 additions & 5 deletions src/database/server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PrismaClient, type tickets } from '@prisma/client';
import { PrismaClient, type ticketsGuild, type ticketsInfo } from '@prisma/client';

export default class ServerData {
private prisma: PrismaClient;
Expand All @@ -7,14 +7,14 @@ export default class ServerData {
this.prisma = new PrismaClient();
}

public async get(guildId: string): Promise<tickets | null> {
let data = await this.prisma.tickets.findUnique({
public async get(guildId: string): Promise<ticketsGuild> {
let data = await this.prisma.ticketsGuild.findUnique({
where: {
guildId,
},
});
if (!data) {
data = await this.prisma.tickets.create({
data = await this.prisma.ticketsGuild.create({
data: {
guildId,
selectMenuOptions: '',
Expand All @@ -27,7 +27,7 @@ export default class ServerData {

public async saveTicketData(guildId: string, options: any): Promise<void> {
try {
await this.prisma.tickets.upsert({
await this.prisma.ticketsGuild.upsert({
where: {
guildId,
},
Expand All @@ -43,4 +43,46 @@ export default class ServerData {
console.error('Error saving ticket data:', error);
}
}

public async getTicketInfo(channelId: string): Promise<ticketsInfo> {
const data = await this.prisma.ticketsInfo.findUnique({
where: {
channelid: channelId,
},
});
return data;
}

public async saveTicketInfo(channelId: string, creator: string): Promise<void> {
try {
await this.prisma.ticketsInfo.upsert({
where: {
channelid: channelId,
},
update: {
creator,
createdAt: BigInt(Date.now()),
},
create: {
channelid: channelId,
creator,
createdAt: BigInt(Date.now()),
},
});
} catch (error) {
console.error('Error saving ticket info:', error);
}
}

public async deleteTicketInfo(channelId: string): Promise<void> {
try {
await this.prisma.ticketsInfo.delete({
where: {
channelid: channelId,
},
});
} catch (error) {
console.error('Error deleting ticket info:', error);
}
}
}
38 changes: 31 additions & 7 deletions src/events/client/InteractionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,17 @@ export default class InteractionCreate extends Event {
shouldCloseTicket = true;
reason = message.content;
await LogsManager.logTicketDeletion(interaction, this.client, interaction.user.username, categoryLabel, channel, reason);
if (config.notifyTicketCreator) {
await this.notifyTicketCreator(interaction, interaction.user, reason, ticketChannel);

const ticket = await this.client.db.getTicketInfo(ticketChannel.id);
if (ticket) {
const creator = interaction.guild.members.cache.find((member) => member.user.username === ticket.creator);
if (creator) {
await this.notifyTicketCreator(interaction, creator, reason, ticketChannel);
} else {
this.client.logger.error(`Failed to find creator of ticket ${ticketChannel.id}.`);
}
} else {
this.client.logger.error(`Failed to find ticket information for ${ticketChannel.id}.`);
}
});

Expand All @@ -302,6 +311,8 @@ export default class InteractionCreate extends Event {
setTimeout(async () => {
try {
await channel.delete(`Ticket closed by user with reason: ${reason}`);

await this.client.db.deleteTicketInfo(channel.id);
} catch (error) {
this.client.logger.error('Failed to delete channel:', error);
}
Expand All @@ -310,8 +321,16 @@ export default class InteractionCreate extends Event {
} else {
const reason = 'No reason provided';
await LogsManager.logTicketDeletion(interaction, this.client, interaction.user.username, categoryLabel, channel, reason);
if (config.notifyTicketCreator) {
await this.notifyTicketCreator(interaction, interaction.user, reason, ticketChannel);
const ticket = await this.client.db.getTicketInfo(ticketChannel.id);
if (ticket) {
const creator = interaction.guild.members.cache.find((member) => member.user.username === ticket.creator);
if (creator) {
await this.notifyTicketCreator(interaction, creator, reason, ticketChannel);
} else {
this.client.logger.error(`Failed to find creator of ticket ${ticketChannel.id}.`);
}
} else {
this.client.logger.error(`Failed to find ticket information for ${ticketChannel.id}.`);
}

const announcementEmbed = new EmbedBuilder()
Expand All @@ -326,6 +345,8 @@ export default class InteractionCreate extends Event {
setTimeout(async () => {
try {
await channel.delete(`Ticket closed by user with reason: ${reason}`);

await this.client.db.deleteTicketInfo(channel.id);
} catch (error) {
this.client.logger.error('Failed to delete channel:', error);
}
Expand All @@ -335,14 +356,15 @@ export default class InteractionCreate extends Event {

private async notifyTicketCreator(interaction: any, user: any, reason: string | null, ticketChannel: TextChannel): Promise<void> {
try {
const ticket = await this.client.db.getTicketInfo(ticketChannel.id);
const reasonText = reason ? `\n\n**Reason:** ${reason}` : '';

const serverName = interaction.guild.name;

const ticketName = ticketChannel.name;

const categoryLabelMatch = ticketChannel.topic?.match(/Ticket Type: (.+)/);
const ticketCategory = categoryLabelMatch ? categoryLabelMatch[1] : 'Unknown';
const createDat = new Date(Number(ticket.createdAt)).toLocaleString();
const creator = interaction.guild.members.cache.find((member) => member.user.username === ticket.creator);
const creatorName = creator ? creator.user.username : ticket.creator;

const embed = new EmbedBuilder()
.setColor('#FF2400')
Expand All @@ -352,7 +374,9 @@ export default class InteractionCreate extends Event {
{ name: 'Server', value: `> ${serverName}`, inline: true },
{ name: 'Ticket', value: `> #${ticketName}`, inline: true },
{ name: 'Category', value: `> ${ticketCategory}`, inline: true },
{ name: 'Ticket Author', value: `> ${creatorName}`, inline: true },
{ name: 'Closed By', value: `> ${interaction.user.username}`, inline: true },
{ name: 'Ticket Creation Time', value: `> ${createDat}`, inline: true },
)
.setThumbnail(interaction.guild.iconURL({ format: 'png', size: 1024 }))
.setFooter({ text: 'Ticket System', iconURL: interaction.user.displayAvatarURL({ extension: 'png', size: 1024 }) })
Expand Down
79 changes: 79 additions & 0 deletions src/utils/TicketManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ interface Config {
embedDescription: string;
};
};
embeds: {
[key: string]: {
color: number;
title: string;
description: string;
timestamp: boolean;
URL: string;
image: string;
thumbnail: string;
footer: {
text: string;
iconURL: string;
};
author: {
name: string;
iconURL: string;
url: string;
};
};
};
}

export class TicketManager {
Expand Down Expand Up @@ -80,6 +100,8 @@ export class TicketManager {

await LogsManager.logTicketCreation(interaction, categoryLabel, client, channel);

await client.db.saveTicketInfo(channel.id, userName);

return channel;
} catch (error) {
client.logger.error(`Failed to create ticket: ${error.message}`);
Expand Down Expand Up @@ -170,6 +192,63 @@ export class TicketManager {
return embed;
}

public static buildEmbed(embedConfig: any): EmbedBuilder {
const embed = new EmbedBuilder();

if (embedConfig.color) {
embed.setColor(embedConfig.color);
}

if (embedConfig.title) {
embed.setTitle(embedConfig.title);
}

if (embedConfig.description) {
embed.setDescription(embedConfig.description);
}

if (embedConfig.timestamp) {
embed.setTimestamp();
}

if (embedConfig.URL) {
embed.setURL(embedConfig.URL);
}

if (embedConfig.image) {
embed.setImage(embedConfig.image);
}

if (embedConfig.thumbnail) {
embed.setThumbnail(embedConfig.thumbnail);
}

if (embedConfig?.footer?.text !== '' && embedConfig?.footer?.text !== null) {
const footerValues = {
text: embedConfig?.footer?.text || undefined,
iconURL:
embedConfig?.footer?.iconURL !== '' && embedConfig?.footer?.iconURL !== null
? embedConfig?.footer?.iconURL || undefined
: undefined,
};
embed.setFooter(footerValues);
}

if (embedConfig?.author?.name !== '' && embedConfig?.author?.name !== null) {
const authorValues = {
name: embedConfig?.author?.name || undefined,
iconURL:
embedConfig?.author?.iconURL !== '' && embedConfig?.author?.iconURL !== null
? embedConfig?.author?.iconURL || undefined
: undefined,
url: embedConfig?.author?.url || undefined,
};
embed.setAuthor(authorValues);
}

return embed;
}

public static async readConfigFile(): Promise<Config> {
try {
const configFile = await fs.readFile('./config.yml', 'utf8');
Expand Down

0 comments on commit b57ef76

Please sign in to comment.