Skip to content

Commit

Permalink
working ticket system
Browse files Browse the repository at this point in the history
  • Loading branch information
PAW122 committed Dec 24, 2024
1 parent a6c4cae commit e25489d
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 55 deletions.
File renamed without changes.
59 changes: 50 additions & 9 deletions commands/moderation/ticket_close.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
jeżeli komenda zostanie użyta na
*/

const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } = require("discord.js");
const Database = require("../../db/database");
const database = new Database(__dirname + "/../../db/files/servers.json");

Expand All @@ -14,27 +14,68 @@ const command = new SlashCommandBuilder()
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages)
.setDescription("Close ticket")

async function execute(interaction, client) {
async function execute(interaction, client) {
const guild_id = interaction.guild.id;
const channel_id = interaction.channel.id;

const settings = database.get(`${guild_id}.tickets_settings`);
database.init()
const settings = database.read(`${guild_id}.ticket_settings`);
if (!settings || !settings.status) {
return interaction.reply({
content: `Ticket system is disabled`,
ephemeral: true
});
}

if(settings.collect_ratings) {
// send embed with emoji's
// handler will check for reactions
// check if ticket is pending
const pending_tickets = await database.read(`${guild_id}.pending_tickets.${channel_id}`);
if (pending_tickets) {
return interaction.reply({
content: `Ticket is already closed`,
ephemeral: true
});
}

// save ticket_close_time in db & in tickets_handler.js add_new_pengind_channel()
if (settings.collect_ratings) {
// send embed with emoji's
const embed = new EmbedBuilder()
.setColor('#0099ff')
.setTitle('Ticket Closed')
.setDescription('Thank you for using our ticket system. \nPlease rate your experience on a scale of 1 to 5.')
.setTimestamp();

await interaction.reply({ embeds: [embed] });
const msg = await interaction.fetchReply();
// console.log(msg);
await msg.react('1️⃣');
await msg.react('2️⃣');
await msg.react('3️⃣');
await msg.react('4️⃣');
await msg.react('5️⃣');


const message_id = msg.id;

/*
dopuki Date.now() nie będzie >= niż ticket_close_time
to wtedy ticket nie zostanie zamknięty
else usuń wpis z db
*/
const data = {
ticket_close_time: Date.now() + 24 * 60 * 60 * 1000,
ticket_opinion: {
user_id: interaction.user.id, // closed by
emoji_list: ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣'],
},
status: true // false = ticket closed
}

// save reactions for emoji handler
database.write(`${guild_id}.pending_tickets.${channel_id}.${message_id}`, data)

return await interaction.channel.send(`Ticket closed. Thank you for using our ticket system. \nPlease rate your experience on a scale of 1 to 5.\nTicket will be closed in 24h`);
}

// save ticket_close_time in db & in tickets_handler.js add_new_pengind_channel()
}

async function help_message(interaction, client) {
Expand All @@ -44,4 +85,4 @@ async function help_message(interaction, client) {
})
}

module.exports = {command, execute, help_message}
module.exports = { command, execute, help_message }
87 changes: 66 additions & 21 deletions commands/moderation/ticket_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
const Database = require("../../db/database");
const database = new Database(__dirname + "/../../db/files/servers.json");

const BotLogs = require("../../handlers/bot_logs_handler")
const BotLogs = require("../../handlers/bot_logs_handler");
const BotLogsHandler = BotLogs.getInstance()

const command = new SlashCommandBuilder()
Expand All @@ -30,16 +30,19 @@ const command = new SlashCommandBuilder()
.addBooleanOption(option => option
.setName("collect_ratings")
.setDescription("ask user for opinion after closing a ticket")
.setRequired(true)
)
.addBooleanOption(option => option
.setName("delete_on_close")
.setDescription("delete ticket whe closed, false = move ticket channel to closed_tickets category")
.setRequired(true)
)
.addBooleanOption(option => option
.setName("status")
.setDescription("turn function on/off")
)

// TODO: add option to set role for ticket review channels
async function execute(interaction, client) {

const collect_ratings = interaction.options.getBoolean("collect_ratings") || false;
Expand All @@ -48,13 +51,6 @@ async function execute(interaction, client) {

const guild_id = interaction.guild.id;

if (!collect_ratings || !delete_on_close) {
return await interaction.reply({
content: `You need to provide all options`,
ephemeral: true
});
}

let data = {
tickets_category: null,
closed_tickets_category_id: null,
Expand All @@ -64,42 +60,91 @@ async function execute(interaction, client) {
}

// search for category names "tickets"
const ticket_category_id = interaction.guild.channels.cache.find(c => c.name === "tickets" && c.type === "GUILD_CATEGORY")?.id;
const ticket_category_id = interaction.guild.channels.cache.find(
c => c.name === "tickets" && c.type === 4
)?.id;

if (!ticket_category_id) {

try {
const category = await interaction.guild.channels.create("tickets", {
type: "GUILD_CATEGORY"
// Tworzenie kategorii, jeśli nie istnieje
const category = await interaction.guild.channels.create({
name: "tickets",
type: 4, // Typ 4 = GUILD_CATEGORY
permissionOverwrites: [
{
id: interaction.guild.id, // ID serwera (domyślna rola @everyone)
deny: ['ViewChannel'], // Zablokuj widoczność kanału dla wszystkich
},
{
id: interaction.client.user.id, // ID bota
allow: ['ViewChannel', 'SendMessages', 'ManageChannels'], // Daj botowi pełny dostęp
},
{
id: interaction.guild.roles.everyone.id, // Alternatywnie ustawienie dla domyślnej roli @everyone
deny: ['ViewChannel'], // Zablokuj dostęp
},
],
});

data.tickets_category = category.id;


if (category) {
interaction.guild.channels.cache.find(c => c.name === "tickets" && c.type === "GUILD_CATEGORY").id
data.tickets_category = category.id
console.log("Category created:");

// Aktualizacja danych z ID nowej kategorii
data.tickets_category = category.id;
}
} catch (err) {
return await interaction.channel.send({
content: `I can't create category for tickets`,
console.error("Error while creating category:", err);

return await interaction.reply({
content: `I can't create a category for tickets.`,
ephemeral: true
});
}
} else {
// Jeśli kategoria istnieje, ustaw dane na jej ID
data.tickets_category = ticket_category_id;
}


// search for category names "closed_tickets"
const closed_tickets_category_id = interaction.guild.channels.cache.find(c => c.name === "closed_tickets" && c.type === "GUILD_CATEGORY")?.id;
const closed_tickets_category_id = interaction.guild.channels.cache.find
(c => c.name === "closed_tickets" && c.type === 4)?.id;

if (!closed_tickets_category_id) {
try {
const category = await interaction.guild.channels.create("closed_tickets", {
type: "GUILD_CATEGORY"
const category = await interaction.guild.channels.create({
name: "closed_tickets",
type: 4, // 4 = GUILD_CATEGORY
permissionOverwrites: [
{
id: interaction.guild.id, // ID serwera (domyślna rola @everyone)
deny: ['ViewChannel'], // Zablokuj widoczność kanału dla wszystkich
},
{
id: interaction.client.user.id, // ID bota
allow: ['ViewChannel', 'SendMessages', 'ManageChannels'], // Daj botowi pełny dostęp
},
{
id: interaction.guild.roles.everyone.id, // Alternatywnie ustawienie dla domyślnej roli @everyone
deny: ['ViewChannel'], // Zablokuj dostęp
},
],
});
if (category) {
interaction.guild.channels.cache.find(c => c.name === "closed_tickets" && c.type === "GUILD_CATEGORY").id
data.closed_tickets_category_id = category.id
}
} catch (err) {
return await interaction.channel.send({
return await interaction.reply({
content: `I can't create category for closed tickets`,
ephemeral: true
});
}

} else {
data.closed_tickets_category_id = closed_tickets_category_id
}

if (!data.tickets_category) {
Expand Down
21 changes: 20 additions & 1 deletion commands/moderation/ticket_stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@

const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");

const Database = require("../../db/database");
const database = new Database(__dirname + "/../../db/files/servers.json");

const command = new SlashCommandBuilder()
.setName("ticket_stats")
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.setDescription("Get ticket's statistics")

async function execute(interaction, client) {

const guild_id = interaction.guild.id;
const data = await database.read(`${guild_id}.closed_tickets`);
let ratings_list = []

Object.values(data).forEach(day => {
day.forEach(ticket => {
ratings_list.push(ticket.rating);
});
});

const average_rating = ratings_list.reduce((a, b) => a + b, 0) / ratings_list.length;


return await interaction.reply({
content: `Average rating: ${average_rating}`,
ephemeral: true
});
}

async function help_message(interaction, client) {
Expand Down
37 changes: 22 additions & 15 deletions commands/normal/ticket.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,23 @@ const command = new SlashCommandBuilder()
.addStringOption(option => option
.setName("title")
.setDescription("set title for the ticket")
.setRequired(true)
)
.addStringOption(option => option
.setName("Description")
.setName("description")
.setDescription("ticket content")
.setRequired(true)
)

function execute(interaction, client) {
async function execute(interaction, client) {

const title = interaction.options.getString("title");
const description = interaction.options.getString("Description");

if (!title || !description) {
return interaction.reply({
content: `You need to provide all options`,
ephemeral: true
});
}

const guild_id = interaction.guild.id;

// check in db is ticket system is enabled
const settings = database.get(`${guild_id}.tickets_settings`);
const settings = database.read(`${guild_id}.ticket_settings`);
const ticket_category_id = settings.tickets_category;
if(!settings || !settings.status || !ticket_category_id) {
return interaction.reply({
Expand All @@ -56,10 +51,22 @@ function execute(interaction, client) {
}

// create ticket channel in tickets category
const ticket_channel = interaction.guild.channels.create(title, {
type: "GUILD_TEXT",
parent: ticket_category_id
const ticket_channel = await interaction.guild.channels.create({
name: `ticket-${interaction.user.id}`,
type: 0, // text channel
parent: ticket_category_id,
permissionOverwrites: [
{
id: interaction.guild.id,
deny: ['ViewChannel'], // Deny view access to everyone
},
{
id: interaction.user.id,
allow: ['ViewChannel'], // Allow view access to the ticket creator
},
],
});

// check is the channel was created
if (!ticket_channel) {
return interaction.reply({
Expand All @@ -75,10 +82,10 @@ function execute(interaction, client) {
embeds: [{
title: title,
description: description,
color: "BLUE",
color: 15844367,
timestamp: new Date(),
footer: {
text: interaction.user.id
text: "use /ticket_close to close ticket"
}
}]
});
Expand Down
15 changes: 6 additions & 9 deletions handlers/emoji_handler.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
const { use } = require("../api/app");
const Database = require("../db/database")
const db = new Database(process.cwd() + "/db/files/servers.json")

/*
TODO:
jezeli user zareaguje na wiadomość ktora nie istnieje,
usunac wpis z db aby nie marnowac czasu na sprawdzanie wiadomosci
*/

async function addEmoji(client, reaction, user) {
if (reaction.partial) {
try {
Expand Down Expand Up @@ -66,14 +71,6 @@ async function addEmoji(client, reaction, user) {
}
}









}

async function removeEmoji(client, reaction, user) {
Expand Down
Loading

0 comments on commit e25489d

Please sign in to comment.