Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General fixes/improvements #200

Merged
merged 12 commits into from
Jul 19, 2023
901 changes: 723 additions & 178 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
},
"homepage": "https://github.com/Sayrix/ticket-bot#readme",
"dependencies": {
"@prisma/client": "^4.16.1",
"@prisma/client": "^5.0.0",
"axios": "^1.4.0",
"better-sqlite3": "^8.4.0",
"discord.js": "^14.11.0",
Expand All @@ -46,16 +46,16 @@
"@types/node": "^20.3.1",
"@types/pg": "^8.10.2",
"@types/websocket": "^1.0.5",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "^3.0.0",
"prisma": "^4.16.1",
"prisma": "^5.0.0",
"rimraf": "^5.0.1",
"typescript": "^5.1.3"
}
Expand Down
14 changes: 7 additions & 7 deletions prisma/docker.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ model tickets {
channelid String @unique
messageid String @unique
category String @db.Text
invited String @default("[]")
reason String
creator String
invited String @default("[]") @db.Text
reason String @db.Text
creator String @db.Text
createdat BigInt
claimedby String?
claimedby String? @db.Text
claimedat BigInt?
closedby String?
closedby String? @db.Text
closedat BigInt?
closereason String?
transcript String?
closereason String? @db.Text
transcript String? @db.Text
}
2 changes: 1 addition & 1 deletion src/commands/close.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default class CloseCommand extends BaseCommand {
)
return interaction
.reply({
content: this.client.locales.ticketOnlyClosableByStaff,
content: this.client.locales.getValue("ticketOnlyClosableByStaff"),
ephemeral: true,
})
.catch((e) => console.log(e));
Expand Down
4 changes: 2 additions & 2 deletions src/commands/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ export default class RenameCommand extends BaseCommand {
if (!(interaction.member as GuildMember | null)?.roles.cache.some((r) => this.client.config.rolesWhoHaveAccessToTheTickets.includes(r.id)))
return interaction
.reply({
content: this.client.locales.ticketOnlyRenamableByStaff,
content: this.client.locales.getValue("ticketOnlyRenamableByStaff"),
ephemeral: true,
})
.catch((e) => console.log(e));

(interaction.channel as TextChannel)?.setName(interaction.options.get("name", true).value as string).catch((e) => console.log(e));
interaction
.reply({ content: this.client.locales.ticketRenamed.replace("NEWNAME", (interaction.channel as TextChannel | null)?.toString() ?? "Unknown"), ephemeral: false })
.reply({ content: this.client.locales.getValue("ticketRenamed").replace("NEWNAME", (interaction.channel as TextChannel | null)?.toString() ?? "Unknown"), ephemeral: false })
.catch((e) => console.log(e)); }
}

Expand Down
16 changes: 8 additions & 8 deletions src/events/interactionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default class InteractionCreateEvent extends BaseEvent {

const tCount = this.client.config.ticketTypes.length;
if(tCount === 0 || tCount > 25) {
await interaction.followUp({content: this.client.locales.invalidConfig, ephemeral: true});
await interaction.followUp({content: this.client.locales.getValue("invalidConfig"), ephemeral: true});
throw new Error("ticketTypes either has nothing or exceeded 25 entries. Please check the config and restart the bot");
}

Expand All @@ -74,7 +74,7 @@ export default class InteractionCreateEvent extends BaseEvent {
if (ticketsOpened >= this.client.config.maxTicketOpened) {
interaction
.editReply({
content: this.client.locales.ticketLimitReached.replace("TICKETLIMIT", this.client.config.maxTicketOpened.toString())
content: this.client.locales.getValue("ticketLimitReached").replace("TICKETLIMIT", this.client.config.maxTicketOpened.toString())
})
.catch((e) => console.log(e));
return;
Expand Down Expand Up @@ -110,15 +110,15 @@ export default class InteractionCreateEvent extends BaseEvent {

if (options.length <= 0) {
interaction.editReply({
content: this.client.locales.noTickets
content: this.client.locales.getValue("noTickets")
});
return;
}

const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
.setCustomId("selectTicketType")
.setPlaceholder(this.client.locales.other.selectTicketTypePlaceholder)
.setPlaceholder(this.client.locales.getSubValue("other", "selectTicketTypePlaceholder"))
.setMaxValues(1)
.addOptions(options)
);
Expand All @@ -136,7 +136,7 @@ export default class InteractionCreateEvent extends BaseEvent {

if (interaction.customId === "close") {
await interaction.deferReply({ ephemeral: true }).catch((e) => console.log(e));
close(interaction, this.client, this.client.locales.other.noReasonGiven);
close(interaction, this.client, this.client.locales.getSubValue("other", "noReasonGiven"));
}

if (interaction.customId === "close_askReason") {
Expand All @@ -157,7 +157,7 @@ export default class InteractionCreateEvent extends BaseEvent {
if (ticketsOpened >= this.client.config.maxTicketOpened) {
interaction
.reply({
content: this.client.locales.ticketLimitReached.replace("TICKETLIMIT", this.client.config.maxTicketOpened.toString()),
content: this.client.locales.getValue("ticketLimitReached").replace("TICKETLIMIT", this.client.config.maxTicketOpened.toString()),
ephemeral: true,
})
.catch((e) => console.log(e));
Expand All @@ -173,7 +173,7 @@ export default class InteractionCreateEvent extends BaseEvent {
if(qCount === 0 || qCount > 5)
throw new Error(`${ticketType.codeName} has either no questions or exceeded 5 questions. Check your config and restart the bot`);

const modal = new ModalBuilder().setCustomId("askReason").setTitle(this.client.locales.modals.reasonTicketOpen.title);
const modal = new ModalBuilder().setCustomId("askReason").setTitle(this.client.locales.getSubValue("modals", "reasonTicketOpen", "title"));
for (const question of ticketType.questions) {
const index = ticketType.questions.indexOf(question);
const input = new TextInputBuilder()
Expand All @@ -189,7 +189,7 @@ export default class InteractionCreateEvent extends BaseEvent {

await interaction.showModal(modal).catch((e) => console.log(e));
} else {
createTicket(interaction, this.client, ticketType, this.client.locales.other.noReasonGiven);
createTicket(interaction, this.client, ticketType, this.client.locales.getSubValue("other", "noReasonGiven"));
}
}

Expand Down
25 changes: 16 additions & 9 deletions src/events/ready.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import readline from "readline";
import axios from "axios";
import {client as WebSocketClient, connection} from "websocket";
import {ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder} from "discord.js";
import {ActionRowBuilder, ButtonBuilder, ButtonStyle, ColorResolvable, EmbedBuilder, Message} from "discord.js";
import os from "os";
import {BaseEvent, ExtendedClient, SponsorType} from "../structure";

Expand Down Expand Up @@ -60,24 +60,31 @@ export default class ReadyEvent extends BaseEvent {
console.error("The channel to open tickets is not a channel!");
process.exit(0);
}

const embedDat = {...this.client.locales.embeds.openTicket};
const footer = embedDat.footer.text.replace("ticket.pm", "");
const locale = this.client.locales;
let footer = locale.getSubValue("embeds", "openTicket", "footer", "text").replace("ticket.pm", "");
// Please respect the project by keeping the credits, (if it is too disturbing you can credit me in the "about me" of the bot discord)
embedDat.footer.text = `ticket.pm ${footer.trim() !== "" ? `- ${footer}` : ""}`; // Please respect the LICENSE :D
footer = `ticket.pm ${footer.trim() !== "" ? `- ${footer}` : ""}`; // Please respect the LICENSE :D
// Please respect the project by keeping the credits, (if it is too disturbing you can credit me in the "about me" of the bot discord)
const embed = new EmbedBuilder({
...embedDat,
color: 0,
})
.setColor(embedDat.color ?? this.client.config.mainColor);
.setTitle(locale.getSubValue("embeds", "openTicket", "title"))
.setDescription(locale.getSubValue("embeds", "openTicket", "description"))
.setColor(locale.getNoErrorSubValue("embeds", "openTicket", "color") as ColorResolvable | undefined ?? this.client.config.mainColor)
.setFooter({text: footer});

const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId("openTicket").setLabel(this.client.locales.other.openTicketButtonMSG).setStyle(ButtonStyle.Primary)
new ButtonBuilder().setCustomId("openTicket").setLabel(this.client.locales.getSubValue("other", "openTicketButtonMSG")).setStyle(ButtonStyle.Primary)
);

try {
const msg = embedMessageId ? await openTicketChannel?.messages?.fetch(embedMessageId).catch((ex) => console.error(ex)) : undefined;
// Fetch Message object and return undefined if not found
const msg = embedMessageId ? await (()=> new Promise<Message | undefined>((res)=> {
openTicketChannel?.messages?.fetch(embedMessageId)
.then(msg=>res(msg))
.catch(()=>res(undefined));
}))() : undefined;

if (msg && msg.id) {
msg.edit({
embeds: [embed],
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ const client = new ExtendedClient({
}, config);

// Login the bot
const token = process.env["TOKEN"];
if(!token || token.trim() === "")
throw new Error("TOKEN Environment Not Found");
client.login(process.env["TOKEN"]).then(null);

/*
Expand Down
2 changes: 1 addition & 1 deletion src/structure/BaseEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default abstract class BaseEvent {
this.client = client;
}

// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line no-unused-vars
protected abstract execute(...args: ClientEvents[keyof ClientEvents]): void | Promise<void>;

}
7 changes: 4 additions & 3 deletions src/structure/ExtendedClient.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import {Client, ClientOptions, Collection, Routes} from "discord.js";
import {BaseCommand, ConfigType, LocaleType} from "./";
import {BaseCommand, ConfigType} from "./";
import {PrismaClient} from "@prisma/client";
import fs from "fs-extra";
import path from "node:path";
import {AddCommand, ClaimCommand, CloseCommand, RemoveCommand, RenameCommand} from "../commands";
import {InteractionCreateEvent, ReadyEvent} from "../events";
import {jsonc} from "jsonc";
import {REST} from "@discordjs/rest";
import {Translation} from "../utils/translation";

export default class ExtendedClient extends Client {
public readonly config: ConfigType;
public readonly prisma: PrismaClient;
public locales: LocaleType;
public locales: Translation;
public commands: Collection<string, BaseCommand>;
constructor(options: ClientOptions, config: ConfigType) {
super(options);

this.config = config;
this.prisma = new PrismaClient();
this.locales = JSON.parse(fs.readFileSync(path.join(__dirname, `../../locales/${this.config.lang}.json`), "utf8"));
this.locales = new Translation(this.config.lang, path.join(__dirname, "../../locales/"));
this.commands = new Collection([
[AddCommand.data.name, new AddCommand(this)],
[ClaimCommand.data.name, new ClaimCommand(this)],
Expand Down
8 changes: 4 additions & 4 deletions src/utils/claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ export const claim = async(interaction: ButtonInteraction | CommandInteraction,
if (!canClaim)
return interaction
.reply({
content: client.locales.ticketOnlyClaimableByStaff,
content: client.locales.getValue("ticketOnlyClaimableByStaff"),
ephemeral: true,
})
.catch((e) => console.log(e));

if (claimed)
return interaction
.reply({
content: client.locales.ticketAlreadyClaimed,
content: client.locales.getValue("ticketAlreadyClaimed"),
ephemeral: true,
})
.catch((e) => console.log(e));
Expand Down Expand Up @@ -74,7 +74,7 @@ export const claim = async(interaction: ButtonInteraction | CommandInteraction,
const msg = await interaction.channel?.messages.fetch(ticket.messageid);
const oldEmbed = msg?.embeds[0].data;
const newEmbed = new EmbedBuilder(oldEmbed)
.setDescription(oldEmbed?.description + `\n\n ${client.locales.other.claimedBy.replace("USER", `<@${interaction.user.id}>`)}`);
.setDescription(oldEmbed?.description + `\n\n ${client.locales.getSubValue("other", "claimedBy").replace("USER", `<@${interaction.user.id}>`)}`);

const row = new ActionRowBuilder<ButtonBuilder>();
msg?.components[0].components.map((x) => {
Expand All @@ -91,7 +91,7 @@ export const claim = async(interaction: ButtonInteraction | CommandInteraction,

interaction
.reply({
content: client.locales.ticketClaimedMessage.replace("USER", `<@${interaction.user.id}>`),
content: client.locales.getValue("ticketClaimedMessage").replace("USER", `<@${interaction.user.id}>`),
ephemeral: false,
})
.catch((e) => console.log(e));
Expand Down
35 changes: 17 additions & 18 deletions src/utils/close.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { generateMessages } from "ticket-bot-transcript-uploader";
import zlib from "zlib";
import axios from "axios";
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, Collection, CommandInteraction, ComponentType, EmbedBuilder, GuildMember, Message, ModalSubmitInteraction, TextChannel } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, Collection, ColorResolvable, CommandInteraction, ComponentType, EmbedBuilder, GuildMember, Message, ModalSubmitInteraction, TextChannel } from "discord.js";
import { log } from "./logs";
import {ExtendedClient} from "../structure";
let domain = "https://ticket.pm/";
Expand Down Expand Up @@ -40,7 +40,7 @@ type ticketType = {
}

export async function close(interaction: ButtonInteraction | CommandInteraction | ModalSubmitInteraction, client: ExtendedClient, reason?: string) {
if (!client.config.closeOption.createTranscript) domain = client.locales.other.unavailable;
if (!client.config.closeOption.createTranscript) domain = client.locales.getSubValue("other","unavailable");

const ticket = await client.prisma.tickets.findUnique({
where: {
Expand All @@ -56,14 +56,14 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
)
return interaction
.editReply({
content: client.locales.ticketOnlyClosableByStaff
content: client.locales.getValue("ticketOnlyClosableByStaff")
})
.catch((e) => console.log(e));

if (ticketClosed)
return interaction
.editReply({
content: client.locales.ticketAlreadyClosed
content: client.locales.getValue("ticketAlreadyClosed")
})
.catch((e) => console.log(e));

Expand Down Expand Up @@ -99,7 +99,7 @@ export async function close(interaction: ButtonInteraction | CommandInteraction

interaction
.editReply({
content: client.locales.ticketCreatingTranscript
content: client.locales.getValue("ticketCreatingTranscript")
})
.catch((e) => console.log(e));
async function _close(id: string, ticket: ticketType) {
Expand All @@ -125,9 +125,9 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
.catch((e) => console.log(e));

interaction.channel?.send({
content: client.locales.ticketTranscriptCreated.replace(
content: client.locales.getValue("ticketTranscriptCreated").replace(
"TRANSCRIPTURL",
domain === client.locales.other.unavailable ? client.locales.other.unavailable : `<${domain}${id}>`
domain === client.locales.getSubValue("other", "unavailable") ? client.locales.getSubValue("other", "unavailable") : `<${domain}${id}>`
)
}).catch((e) => console.log(e));

Expand All @@ -136,23 +136,23 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
closedby: interaction.user.id,
closedat: Date.now(),
closereason: reason,
transcript: domain === client.locales.other.unavailable ? client.locales.other.unavailable : `${domain}${id}`
transcript: domain === client.locales.getSubValue("other", "unavailable") ? client.locales.getSubValue("other", "unavailable") : `${domain}${id}`
},
where: {
channelid: interaction.channel?.id
}
});

const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId("deleteTicket").setLabel(client.locales.other.deleteTicketButtonMSG).setStyle(ButtonStyle.Danger)
new ButtonBuilder().setCustomId("deleteTicket").setLabel(client.locales.getSubValue("other", "deleteTicketButtonMSG")).setStyle(ButtonStyle.Danger)
);
const lEmbed = client.locales.embeds;
const locale = client.locales;
interaction.channel?.send({
embeds: [
JSON.parse(
JSON.stringify(lEmbed.ticketClosed)
JSON.stringify(locale.getSubValue("embeds", "ticketClosed"))
.replace("TICKETCOUNT", ticket.id.toString())
.replace("REASON", (ticket.closereason ?? client.locales.other.noReasonGiven).replace(/[\n\r]/g, "\\n"))
.replace("REASON", (ticket.closereason ?? client.locales.getSubValue("other", "noReasonGiven")).replace(/[\n\r]/g, "\\n"))
.replace("CLOSERNAME", interaction.user.tag)
)
],
Expand All @@ -162,24 +162,23 @@ export async function close(interaction: ButtonInteraction | CommandInteraction


if(!client.config.closeOption.dmUser) return;
const footer = lEmbed.ticketClosedDM.footer.text.replace("ticket.pm", "");
const footer = locale.getSubValue("embeds", "ticketClosedDM", "footer", "text").replace("ticket.pm", "");
const ticketClosedDMEmbed = new EmbedBuilder({
...lEmbed,
color: 0,
})
.setColor(lEmbed.ticketClosedDM.color ?? client.config.mainColor)
.setColor(locale.getSubValue("ticketClosedDM", "color") as ColorResolvable ?? client.config.mainColor)
.setDescription(
client.locales.embeds.ticketClosedDM.description
client.locales.getSubValue("embeds", "ticketClosedDM", "description")
.replace("TICKETCOUNT", ticket.id.toString())
.replace("TRANSCRIPTURL", `[\`${domain}${id}\`](${domain}${id})`)
.replace("REASON", ticket.closereason ?? client.locales.other.noReasonGiven)
.replace("REASON", ticket.closereason ?? client.locales.getSubValue("other", "noReasonGiven"))
.replace("CLOSERNAME", interaction.user.tag)
)
.setFooter({
// Please respect the project by keeping the credits, (if it is too disturbing you can credit me in the "about me" of the bot discord)
text: `ticket.pm ${footer.trim() !== "" ? `- ${footer}` : ""}`, // Please respect the LICENSE :D
// Please respect the project by keeping the credits, (if it is too disturbing you can credit me in the "about me" of the bot discord)
iconURL: lEmbed.ticketClosedDM.footer.iconUrl
iconURL: locale.getSubValue("embeds", "ticketClosedDM", "footer", "iconUrl")
});

client.users.fetch(creator).then((user) => {
Expand Down
Loading