Skip to content

Commit

Permalink
Merge pull request #172 from Sayrix/v3-feat
Browse files Browse the repository at this point in the history
v3.0.0 Features
  • Loading branch information
Sayrix authored Jun 26, 2023
2 parents ea37273 + 72c7731 commit 024b107
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 51 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ The documentation is available [here](https://doc.ticket.pm/)
## ⚠️ Incompatibility
This new source code you're seeing are completely refactored and will be incompatible with the older version.
I recommend you finish up all of your remaining support ticket and start migrating to the newer version.
If you prefer to stay in the older version, you can download anything that is less than `3.0.0` from the release
or clone from the `old` branch (i.e. `git clone -b old https://github.com/Sayrix/Ticket-Bot.git`)
If you prefer to stay in the older version, here is the doc for the old version: https://doc.ticket.pm/docs/oldDoc/intro

## 💬 Discord

Expand All @@ -23,6 +22,11 @@ You can come on the discord: https://discord.gg/VasYV6MEJy

Contributions are welcome! Please read the [contributing guidelines](https://github.com/Sayrix/Ticket-Bot/blob/main/CONTRIBUTING.md) first.

## 👨‍💻 Maintainers
Our current project maintainers:
* [Sayrix](https://github.com/Sayrix)
* [小兽兽/zhiyan114](https://github.com/zhiyan114)

## 💎 Sponsors
Thanks to all our sponsors! 🙏
You can see all perks here: https://github.com/sponsors/Sayrix
Expand Down
28 changes: 17 additions & 11 deletions config/config.example.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
"mainColor": "#f6c42f", // The hex color of the embeds by default
"lang": "main", // If you want to set english please set "main"

"closeTicketCategoryId": "", // The id of the category where a closed ticket will be moved to. Leave blank to disable this feature

"openTicketChannelId": "1111111111111111111", // The id of the channel where the message to create a ticket will be sent

"ticketTypes": [
Expand Down Expand Up @@ -58,7 +56,14 @@
}
],
"ticketNameOption": "Ticket-TICKETCOUNT", // Here is all parameter: USERNAME, USERID, TICKETCOUNT
"ticketNamePrefixWhenClaimed": "✔️", // With ✔️ as prefix the name of the ticket will be like this: ✔️ticket-1

// Ticket Claim Options
"claimOption": {
"claimButton": true, // Whether to enable ticket claim button or not
// The X can be replaced with S (The staff that claimed the ticket) or U (The user that created the ticket)
"nameWhenClaimed": "✔️ Ticket-TICKETCOUNT", // Here is all parameter: X_USERNAME, X_USERID, TICKETCOUNT
"categoryWhenClaimed": "" // The category the ticket is moved to when claimed
},

"rolesWhoHaveAccessToTheTickets": ["1111111111111111111", "2222222222222222222"], // Roles who can access to the tickets (Like the staff)

Expand All @@ -69,14 +74,15 @@

"logs": true,
"logsChannelId": "1111111111111111111", // The id of the channel where the logs will be sent

"claimButton": true,

"whoCanCloseTicket": "STAFFONLY", // STAFFONLY (roles configured at "rolesWhoHaveAccessToTheTickets") or EVERYONE
"closeButton": true, // If false the ticket can be closed only by doing /closes
"askReasonWhenClosing": true, // If false the ticket will be closed without asking the reason

"createTranscript": true, // If set to true, when the ticket is closed a transcript will be generated and sent in the logs channel

"closeOption": {
"closeButton": true, // If false the ticket can be closed only by doing /closes
"dmUser": true, // Whether to DM the user when the ticket is closed
"createTranscript": true, // If set to true, when the ticket is closed a transcript will be generated and sent in the logs channel
"askReason": true, // If false the ticket will be closed without asking the reason
"whoCanCloseTicket": "STAFFONLY", // STAFFONLY (roles configured at "rolesWhoHaveAccessToTheTickets") or EVERYONE
"closeTicketCategoryId": "" // The id of the category where a closed ticket will be moved to. Leave blank to disable this feature
},
"uuidType": "uuid", // uuid or emoji

"status": {
Expand Down
2 changes: 1 addition & 1 deletion prisma/compatible.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS tickets (
id SERIAL PRIMARY KEY,
channelid TEXT NOT NULL UNIQUE,
messageid TEXT NOT NULL UNIQUE,
category TEXT NOT NULL,
category LONGTEXT NOT NULL,
invited TEXT NOT NULL DEFAULT '[]',
reason TEXT NOT NULL,
creator TEXT NOT NULL,
Expand Down
2 changes: 1 addition & 1 deletion prisma/postgre.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ this will be used for

CREATE TABLE IF NOT EXISTS config (
key VARCHAR(256) PRIMARY KEY,
value TEXT
value LONGTEXT
);

/*
Expand Down
21 changes: 14 additions & 7 deletions src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,26 @@ export type config = {
openTicketChannelId: string;
ticketTypes: TicketType[];
ticketNameOption: string;
ticketNamePrefixWhenClaimed: string;
claimOption: {
claimButton: boolean;
nameWhenClaimed?: string;
categoryWhenClaimed?: string;
};
rolesWhoHaveAccessToTheTickets: string[];
rolesWhoCanNotCreateTickets: string[];
pingRoleWhenOpened: boolean;
roleToPingWhenOpenedId: string[];
logs: boolean;
logsChannelId: string;
claimButton: boolean;
whoCanCloseTicket: "STAFFONLY" | "EVERYONE";
closeButton: boolean;
askReasonWhenClosing: boolean;
createTranscript: boolean;
uuidType: string,
closeOption: {
closeButton: boolean;
dmUser: boolean;
createTranscript: boolean;
askReason: boolean;
whoCanCloseTicket: "STAFFONLY" | "EVERYONE";
closeTicketCategoryId?: string;
};
uuidType: "uuid" | "emoji";
status: {
enabled: boolean;
text: string;
Expand Down
4 changes: 2 additions & 2 deletions src/commands/close.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default {
data: new SlashCommandBuilder().setName("close").setDescription("Close the ticket"),
async execute(interaction: CommandInteraction, client: DiscordClient) {
if (
client.config.whoCanCloseTicket === "STAFFONLY" &&
client.config.closeOption.whoCanCloseTicket === "STAFFONLY" &&
!(interaction.member as GuildMember | null)?.roles.cache.some((r) => client.config.rolesWhoHaveAccessToTheTickets.includes(r.id))
)
return interaction
Expand All @@ -33,7 +33,7 @@ export default {
})
.catch((e) => console.log(e));

if (client.config.askReasonWhenClosing) {
if (client.config.closeOption.askReason) {
closeAskReason(interaction, client);
} else {
await interaction.deferReply().catch((e) => console.log(e));
Expand Down
10 changes: 8 additions & 2 deletions src/events/ready.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,16 @@ export default {
embeds: [embed],
components: [row]
}).then((rMsg) => {
client.prisma.config.create({
data: {
client.prisma.config.upsert({
create: {
key: "openTicketMessageId",
value: rMsg.id
},
update: {
value: rMsg.id
},
where: {
key: "openTicketMessageId"
}
}).then(); // I need .then() for it to execute?!?!??
});
Expand Down
26 changes: 21 additions & 5 deletions src/utils/claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, CommandInteraction, EmbedBuilder, GuildMember, TextChannel } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ChannelType, CommandInteraction, EmbedBuilder, GuildMember, TextChannel } from "discord.js";
import { DiscordClient } from "../Types";
import { log } from "./logs";

Expand All @@ -24,7 +24,7 @@ import { log } from "./logs";
* @param {Discord.Client} client
*/
export const claim = async(interaction: ButtonInteraction | CommandInteraction, client: DiscordClient) => {
const ticket = await client.prisma.tickets.findUnique({
let ticket = await client.prisma.tickets.findUnique({
where: {
channelid: interaction.channel?.id
}
Expand Down Expand Up @@ -66,7 +66,7 @@ export const claim = async(interaction: ButtonInteraction | CommandInteraction,
client
);

await client.prisma.tickets.update({
ticket = await client.prisma.tickets.update({
data: {
claimedby: interaction.user.id,
claimedat: Date.now()
Expand Down Expand Up @@ -101,9 +101,25 @@ export const claim = async(interaction: ButtonInteraction | CommandInteraction,
})
.catch((e) => console.log(e));

if (client.config.ticketNamePrefixWhenClaimed) {
(interaction.channel as TextChannel | null)?.setName(`${client.config.ticketNamePrefixWhenClaimed}${(interaction.channel as TextChannel | null)?.name}`).catch((e) => console.log(e));
const defaultName = client.config.claimOption.nameWhenClaimed;
if (defaultName && defaultName.trim() !== "") {
const creatorUser = await client.users.fetch(ticket.creator);
const newName = defaultName
.replaceAll("S_USERNAME", interaction.user.username)
.replaceAll("U_USERNAME", creatorUser.username)
.replaceAll("S_USERID", interaction.user.id)
.replaceAll("U_USERID", creatorUser.id)
.replaceAll("TICKETCOUNT", ticket.id.toString());
await (interaction.channel as TextChannel | null)?.setName(newName).catch((e) => console.log(e));
}

const categoryID = client.config.claimOption.categoryWhenClaimed;
if(categoryID && categoryID.trim() !== "") {
const category = await interaction.guild?.channels.fetch(categoryID);
if(category?.type !== ChannelType.GuildCategory)
return console.error("claim.ts: USER ERROR - Invalid categoryWhenClaimed ID. Channel must be a category.");
await (interaction.channel as TextChannel | null)?.setParent(category);
}
};
/*
Copyright 2023 Sayrix (github.com/Sayrix)
Expand Down
42 changes: 26 additions & 16 deletions src/utils/close.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,26 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

type ticketType = {
id: number;
channelid: string;
messageid: string;
category: string;
invited: string;
reason: string;
creator: string;
createdat: bigint;
claimedby: string | null;
claimedat: bigint | null;
closedby: string | null;
closedat: bigint | null;
closereason: string | null;
transcript: string | null;
}

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

const ticket = await client.prisma.tickets.findUnique({
where: {
Expand All @@ -33,7 +51,7 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
if (!ticket) return interaction.editReply({ content: "Ticket not found" }).catch((e) => console.log(e));

if (
client.config.whoCanCloseTicket === "STAFFONLY" &&
client.config.closeOption.whoCanCloseTicket === "STAFFONLY" &&
!(interaction.member as GuildMember | null)?.roles.cache.some((r) => client.config.rolesWhoHaveAccessToTheTickets.includes(r.id))
)
return interaction
Expand Down Expand Up @@ -84,19 +102,9 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
content: client.locales.ticketCreatingTranscript
})
.catch((e) => console.log(e));

async function _close(id: string) {
async function _close(id: string, ticket: ticketType) {
if (client.config.closeTicketCategoryId) (interaction.channel as TextChannel | null)?.setParent(client.config.closeTicketCategoryId).catch((e) => console.log(e));

// We can guarantee this is not null because it's already checked above.
// Should re-write this to prevent nested functions :/
let ticket = (await client.prisma.tickets.findUnique({
where: {
channelid: interaction.channel?.id
}
}));
if(!ticket) return console.error("close.ts: UNEXPECTED ERROR - _close func encountered null ticket");

const msg = await interaction.channel?.messages.fetch(ticket.messageid);
const embed = new EmbedBuilder(msg?.embeds[0].data);

Expand Down Expand Up @@ -152,6 +160,8 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
})
.catch((e) => console.log(e));


if(!client.config.closeOption.dmUser) return;
const footer = lEmbed.ticketClosedDM.footer.text.replace("ticket.pm", "");
const ticketClosedDMEmbed = new EmbedBuilder({
...lEmbed,
Expand Down Expand Up @@ -181,8 +191,8 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
});
}

if (!client.config.createTranscript) {
_close("");
if (!client.config.closeOption.createTranscript) {
_close("", ticket);
return;
}

Expand Down Expand Up @@ -223,7 +233,7 @@ export async function close(interaction: ButtonInteraction | CommandInteraction
}
})
.catch(console.error);
_close(ts?.data);
_close(ts?.data, ticket);
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/close_askReason.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { DiscordClient } from "../Types";

export const closeAskReason = async(interaction: CommandInteraction | ButtonInteraction, client: DiscordClient) => {
if (
client.config.whoCanCloseTicket === "STAFFONLY" &&
client.config.closeOption.whoCanCloseTicket === "STAFFONLY" &&
!(interaction.member as GuildMember | null)?.roles.cache.some((r) => client.config.rolesWhoHaveAccessToTheTickets.includes(r.id))
)
return interaction
Expand Down
6 changes: 3 additions & 3 deletions src/utils/createTicket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ export const createTicket = async (interaction: StringSelectMenuInteraction | Mo

const row = new ActionRowBuilder<ButtonBuilder>();

if (client.config.closeButton) {
if (client.config.askReasonWhenClosing) {
if (client.config.closeOption.closeButton) {
if (client.config.closeOption.askReason) {
row.addComponents(
new ButtonBuilder()
.setCustomId("close_askReason")
Expand All @@ -176,7 +176,7 @@ export const createTicket = async (interaction: StringSelectMenuInteraction | Mo
}
}

if (client.config.claimButton) {
if (client.config.claimOption.claimButton) {
row.addComponents(
new ButtonBuilder()
.setCustomId("claim")
Expand Down

0 comments on commit 024b107

Please sign in to comment.