Did stuff, test file
This commit is contained in:
parent
af8eaa1a02
commit
9aa941a563
|
|
@ -1,18 +1,83 @@
|
|||
{
|
||||
"token": "",
|
||||
"staff_channel": "",
|
||||
"database_file": "database.db",
|
||||
"joinleave-logs": "",
|
||||
"staff_channel": "",
|
||||
"staff_msg_autodelete_time": 30,
|
||||
"ticket_category": "",
|
||||
"ticket_bot": "",
|
||||
"ticket_detect_phrase": "Welcome",
|
||||
"ticket_channel_prefix": "ticket-",
|
||||
"staff_ping": "@here",
|
||||
"questions": [
|
||||
{
|
||||
"type": 1,
|
||||
"components": [
|
||||
{
|
||||
"type": 4,
|
||||
"custom_id": "question_1",
|
||||
"label": "Are you a Satanist?",
|
||||
"style": 1,
|
||||
"required": true,
|
||||
"placeholder": "Yes or No",
|
||||
"min_length": 2,
|
||||
"max_length": 10
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"custom_id": "question_2",
|
||||
"label": "What does the word 'Satan' mean to you?",
|
||||
"style": 1,
|
||||
"required": true,
|
||||
"placeholder": "Your answer",
|
||||
"min_length": 5,
|
||||
"max_length": 100
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"custom_id": "question_3",
|
||||
"label": "What about Satanism is appealing to you?",
|
||||
"style": 1,
|
||||
"required": true,
|
||||
"placeholder": "Your answer",
|
||||
"min_length": 10,
|
||||
"max_length": 100
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"custom_id": "question_4",
|
||||
"label": "What is the purpose of joining this server?",
|
||||
"style": 1,
|
||||
"required": true,
|
||||
"placeholder": "Your answer",
|
||||
"min_length": 10,
|
||||
"max_length": 100
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"custom_id": "question_5",
|
||||
"label": "Are you here to learn more about non-theistic Satanism?",
|
||||
"style": 1,
|
||||
"required": true,
|
||||
"placeholder": "Yes or No",
|
||||
"min_length": 2,
|
||||
"max_length": 10
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"custom_id": "question_6",
|
||||
"label": "Are you theistic, or atheistic?",
|
||||
"style": 1,
|
||||
"required": true,
|
||||
"placeholder": "Theistic or Atheistic",
|
||||
"min_length": 5,
|
||||
"max_length": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"auto_accept": {
|
||||
"threshold": 4,
|
||||
"remove_roles": [""],
|
||||
"add_roles": [""],
|
||||
"welcome_message": "Welcome %user%! Please be sure to read <#> and get some <#>!",
|
||||
"welcome_channel": ""
|
||||
},
|
||||
"ntfyUrl": ""
|
||||
}
|
||||
}
|
||||
BIN
database.db
Normal file
BIN
database.db
Normal file
Binary file not shown.
2926
package-lock.json
generated
2926
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,6 +10,7 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"colors": "^1.4.0",
|
||||
"discord.js": "^14.14.1"
|
||||
"discord.js": "^14.14.1",
|
||||
"sqlite3": "^5.1.7"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
657
test.js
Normal file
657
test.js
Normal file
|
|
@ -0,0 +1,657 @@
|
|||
const config = require("./config.json");
|
||||
const { Client, REST, Routes, InteractionType, ButtonStyle, MessageFlags, ComponentType, ChannelType } = require("discord.js");
|
||||
const client = new Client({ intents: ["Guilds", "MessageContent", "GuildMessages"] });
|
||||
const rest = new REST().setToken(config.token);
|
||||
const sqlite3 = require("sqlite3").verbose();
|
||||
const db = new sqlite3.Database(config.database_file || "database.db");
|
||||
|
||||
db.run(`CREATE TABLE IF NOT EXISTS tickets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
data BLOB NOT NULL DEFAULT '{}'
|
||||
)`);
|
||||
|
||||
let ticketCategory;
|
||||
let staffChannel;
|
||||
|
||||
const genTranscript = async (channel) => {
|
||||
let messages = [];
|
||||
let lastId;
|
||||
while (true) {
|
||||
let fetched = await channel.messages.fetch({ limit: 100, before: lastId });
|
||||
if (fetched.size === 0) break;
|
||||
messages = messages.concat(Array.from(fetched.values()));
|
||||
lastId = fetched.last().id;
|
||||
}
|
||||
messages = messages.sort((a, b) => a.createdTimestamp - b.createdTimestamp);
|
||||
let transcript = messages.map(m => `[${new Date(m.createdTimestamp).toISOString()}] ${m.author.tag} (${m.author.id}): ${m.content}`).join("\n");
|
||||
return transcript;
|
||||
}
|
||||
|
||||
|
||||
client.once('clientReady', async () => {
|
||||
console.log(`Logged in as ${client.user.displayName}`);
|
||||
try {
|
||||
console.log("Updating commands")
|
||||
await rest.put(
|
||||
Routes.applicationCommands(client.user.id),
|
||||
{
|
||||
body: [
|
||||
{
|
||||
name: 'postbutton',
|
||||
description: 'Posts a button to the channel',
|
||||
default_member_permissions: "0" // Admin only
|
||||
},
|
||||
{
|
||||
name: "unbreak",
|
||||
description: "Unbreak a ticket (force delete it from the database, last resort!)",
|
||||
default_member_permissions: "0", // Admin only
|
||||
options: [
|
||||
{
|
||||
name: "user",
|
||||
description: "The user to unbreak",
|
||||
type: 6, // USER type
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
);
|
||||
console.log("Commands updated")
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
// Get some stuff ready
|
||||
await client.guilds.fetch(config.guild_id);
|
||||
await client.guilds.cache.get(config.guild_id).channels.fetch();
|
||||
ticketCategory = config.ticket_category ? await client.guilds.cache.get(config.guild_id).channels.fetch(config.ticket_category).catch(() => null) : null;
|
||||
staffChannel = config.staff_channel ? await client.guilds.cache.get(config.guild_id).channels.fetch(config.staff_channel).catch(() => null) : null;
|
||||
})
|
||||
|
||||
client.on('interactionCreate', async interaction => {
|
||||
switch (interaction.type) {
|
||||
case InteractionType.ApplicationCommand:
|
||||
switch (interaction.commandName) {
|
||||
case 'unbreak':
|
||||
let userId = interaction.options.getUser("user").id;
|
||||
db.get(`SELECT * FROM tickets WHERE user_id = ?`, [userId], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while checking the ticket.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (row) {
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while deleting the ticket.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
await interaction.reply({ content: `Successfully unbroke ticket for <@${userId}>.`, flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
await interaction.reply({ content: `<@${userId}> does not have a broken ticket.`, flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'postbutton':
|
||||
await interaction.channel.send({
|
||||
content: config.button_message || "Here is a button!",
|
||||
components: [
|
||||
{
|
||||
type: 1,
|
||||
components: [
|
||||
{
|
||||
type: 2,
|
||||
label: config.button_label || "Click Me",
|
||||
style: ButtonStyle.Success,
|
||||
custom_id: "new-ticket"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
await interaction.reply({ content: "Button posted!", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case InteractionType.MessageComponent:
|
||||
let comm = interaction.customId.split('_')[0];
|
||||
switch (comm) {
|
||||
case 'new-ticket':
|
||||
// Check if user already has a ticket
|
||||
db.get(`SELECT * FROM tickets WHERE user_id = ?`, [interaction.user.id], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while checking your tickets.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (row) {
|
||||
// Check if the channel still exists, if not, delete the ticket from the database and tell the user we fixed things and to press the button again
|
||||
let existingChannel = await interaction.guild.channels.fetch(row.channel_id).catch(() => null);
|
||||
if (!existingChannel) {
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while checking your tickets.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
await interaction.reply({ content: "Your previous ticket channel was missing, but we've fixed it. Please press the button again to create a new ticket.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
await interaction.reply({ content: `You already have an open ticket: <#${row.channel_id}>`, flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// ticket id first part of a uuid
|
||||
let ticket_id = Math.random().toString(36).substring(2, 8);
|
||||
|
||||
// Create ticket channel
|
||||
let channel = await interaction.guild.channels.create({
|
||||
name: `ticket-${ticket_id}`,
|
||||
type: ChannelType.GuildText,
|
||||
|
||||
parent: ticketCategory,
|
||||
permissionOverwrites: [
|
||||
{
|
||||
id: interaction.guild.roles.everyone,
|
||||
deny: ['ViewChannel']
|
||||
},
|
||||
{
|
||||
id: interaction.user.id,
|
||||
allow: ['ViewChannel', 'SendMessages', 'ReadMessageHistory']
|
||||
},
|
||||
...((config.staff_roles || []).map(roleId => ({
|
||||
id: roleId,
|
||||
allow: ['ViewChannel', 'SendMessages', 'ReadMessageHistory']
|
||||
})))
|
||||
]
|
||||
});
|
||||
// Insert into database
|
||||
db.run(`INSERT INTO tickets (user_id, channel_id, data) VALUES (?, ?, ?)`, [interaction.user.id, channel.id, JSON.stringify({ user_answers: {}, staff_answers: {}, question: 0 })], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await channel.send("An error occurred while creating your ticket. Please contact staff.");
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.send({
|
||||
content: `# ${config.formData.title}\n\n${config.formData.description}\n\n*Please answer the following questions by responding in this channel.*`, components: [
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.Button,
|
||||
label: "Close Ticket",
|
||||
style: ButtonStyle.Danger,
|
||||
custom_id: "close-ticket"
|
||||
},
|
||||
{
|
||||
type: ComponentType.Button,
|
||||
label: "Restart Form",
|
||||
style: ButtonStyle.Secondary,
|
||||
custom_id: "restart-form"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
await channel.send({ content: `(1/${config.formData.questions.length}) ${config.formData.questions[0]}` }); // First question
|
||||
});
|
||||
await interaction.reply({ content: `Your ticket has been created: <#${channel.id}>`, flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
case 'close-ticket':
|
||||
// Check if interaction is in a ticket channel
|
||||
db.get(`SELECT * FROM tickets WHERE channel_id = ?`, [interaction.channel.id], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while checking this ticket.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
return;
|
||||
});
|
||||
}
|
||||
if (row) {
|
||||
// Create transcript and delete channel
|
||||
await interaction.reply({ content: "Closing ticket...", flags: [MessageFlags.Ephemeral] });
|
||||
// Fetch all messages in channel
|
||||
let messages = [];
|
||||
let lastId;
|
||||
while (true) {
|
||||
let fetched = await interaction.channel.messages.fetch({ limit: 100, before: lastId });
|
||||
if (fetched.size === 0) break;
|
||||
messages = messages.concat(Array.from(fetched.values()));
|
||||
lastId = fetched.last().id;
|
||||
}
|
||||
messages = messages.sort((a, b) => a.createdTimestamp - b.createdTimestamp);
|
||||
// Generate a txt file transcript
|
||||
let transcript = messages.map(m => `[${new Date(m.createdTimestamp).toISOString()}] ${m.author.tag}: ${m.content}`).join("\n");
|
||||
// Send transcript to staff channel
|
||||
if (staffChannel) {
|
||||
await staffChannel.send({ content: `Transcript for ticket by <@${row.user_id}>:`, files: [{ attachment: Buffer.from(transcript, 'utf-8'), name: `transcript-${interaction.channel.name}.txt` }] });
|
||||
}
|
||||
// Delete ticket from database
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
await interaction.channel.delete("Ticket closed");
|
||||
});
|
||||
} else {
|
||||
await interaction.reply({ content: "This channel is not a ticket channel.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'restart-form':
|
||||
// Check if interaction is in a ticket channel
|
||||
db.get(`SELECT * FROM tickets WHERE channel_id = ?`, [interaction.channel.id], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while checking this ticket.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
return;
|
||||
});
|
||||
}
|
||||
if (row) {
|
||||
// Reset form data
|
||||
let parsed = JSON.parse(row.data);
|
||||
parsed.user_answers = {};
|
||||
parsed.question = 0;
|
||||
db.run(`UPDATE tickets SET data = ? WHERE id = ?`, [JSON.stringify(parsed), row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while resetting the form.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
return;
|
||||
});
|
||||
}
|
||||
await interaction.reply({ content: "The form has been restarted.", flags: [MessageFlags.Ephemeral] });
|
||||
await interaction.channel.send({ content: `(1/${config.formData.questions.length}) ${config.formData.questions[0]}`});
|
||||
});
|
||||
} else {
|
||||
await interaction.reply({ content: "This channel is not a ticket channel.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'staff':
|
||||
// Handle staff options here
|
||||
// split to get option id, and ticket channel
|
||||
let optionId = interaction.customId.split('_')[2];
|
||||
let ticketChannel = interaction.customId.split('_')[1]
|
||||
// Check if the ticket is still valid, if not something VERY bad happened.
|
||||
db.get(`SELECT * FROM tickets WHERE channel_id = ?`, [ticketChannel], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while processing this action.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
return;
|
||||
});
|
||||
}
|
||||
if (row) {
|
||||
// Valid ticket, process the option
|
||||
// Add the count for staff option picked, check auto actions to see if any need to be performed
|
||||
let ticketData = JSON.parse(row.data);
|
||||
if (!ticketData.staff_answers[optionId]) {
|
||||
ticketData.staff_answers[optionId] = []; // List of staff user IDs that picked the option.
|
||||
}
|
||||
// Find all other options the staff member picked and remove their ID from those lists
|
||||
for (const [otherOptionId, userList] of Object.entries(ticketData.staff_answers)) {
|
||||
ticketData.staff_answers[otherOptionId] = userList.filter(id => id !== interaction.user.id);
|
||||
}
|
||||
// Add staff member to selected option
|
||||
ticketData.staff_answers[optionId].push(interaction.user.id);
|
||||
// Update database
|
||||
db.run(`UPDATE tickets SET data = ? WHERE id = ?`, [JSON.stringify(ticketData), row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
await interaction.reply({ content: "An error occurred while processing this action.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
return;
|
||||
});
|
||||
}
|
||||
try {
|
||||
|
||||
await interaction.reply({ content: `You have selected the option: ${config.formData.staff_options[optionId].label}`, flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
|
||||
// Auto action stuff (under formData)
|
||||
for (const [id, option] of Object.entries(config.formData.staff_options)) {
|
||||
if (!option.auto_actions) continue;
|
||||
const minTrig = (option.auto_actions && option.auto_actions.minimum_trig) || 1;
|
||||
const votes = ticketData.staff_answers[id] ? ticketData.staff_answers[id].length : 0;
|
||||
const acts = option.auto_actions;
|
||||
if (votes >= minTrig) {
|
||||
|
||||
if (acts.close_staff_notif) { // Just disable more staff votes (edit the staff message)
|
||||
// Update staff msg with counts
|
||||
let staffMsg = await staffChannel.messages.fetch(ticketData.staff_message_id).catch(() => console.error);
|
||||
if (staffMsg) {
|
||||
// Edit message to update counts
|
||||
let staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** ${ticketData.staff_answers[id] ? ticketData.staff_answers[id].length : 0}`).join("\n");
|
||||
await staffMsg.edit({
|
||||
content: `@here New ticket completed by <@${row.user_id}> in <#${row.channel_id}>.\n\n**Responses:**\n${Object.entries(ticketData.user_answers).map(([index, answer]) => `**Q${parseInt(index) + 1}:** ${config.formData.questions[index]}\n**A:** ${answer}`).join("\n\n")}\n\n${staffResponseCounters}\n\n# Staff voting closed`
|
||||
});
|
||||
await staffMsg.components[0].components.forEach(component => {
|
||||
component.disabled = true;
|
||||
});
|
||||
await staffMsg.edit({ components: staffMsg.components });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (acts.send_message) { // Send messages places
|
||||
if (acts.send_message.in_ticket && acts.send_message.in_ticket?.enabled) {
|
||||
if (!(acts.kick || acts.ban || acts.close_ticket)) {
|
||||
interaction.guild.channels.cache.get(row.channel_id).send(acts.send_message.in_ticket.message.replaceAll(/%user%/g, `<@${row.user_id}>`)).catch(() => { });
|
||||
}
|
||||
}
|
||||
if (acts.send_message.to_user && acts.send_message.to_user?.enabled) {
|
||||
interaction.guild.members.fetch(row.user_id).then(member => {
|
||||
member.send(acts.send_message.to_user.message.replaceAll(/%user%/g, `<@${row.user_id}>`)).catch(() => { });
|
||||
}).catch(() => { });
|
||||
}
|
||||
if (acts.send_message.external && acts.send_message.external?.enabled && acts.send_message.external?.channel_id) {
|
||||
interaction.guild.channels.fetch(acts.send_message.external.channel_id).then(channel => {
|
||||
channel.send(acts.send_message.external.message.replaceAll(/%user%/g, `<@${row.user_id}>`)).catch(() => { });
|
||||
}).catch(() => { });
|
||||
}
|
||||
}
|
||||
|
||||
if (acts.ban) return interaction.guild.members.fetch(row.user_id).then(async member => {
|
||||
member.ban({ reason: acts.ban_reason || "Banned by staff vote via ticket system." }).catch(() => { });
|
||||
// Do ticket close processing
|
||||
let transcript = await genTranscript(interaction.guild.channels.cache.get(row.channel_id));
|
||||
if (staffChannel) {
|
||||
await staffChannel.send({ content: `Transcript for ticket by <@${row.user_id}> (banned):`, files: [{ attachment: Buffer.from(transcript, 'utf-8'), name: `transcript-${interaction.channel.name}.txt` }] });
|
||||
}
|
||||
|
||||
// Update staff msg
|
||||
let staffMsg = await staffChannel.messages.fetch(ticketData.staff_message_id).catch(() => console.error);
|
||||
if (staffMsg) {
|
||||
// Edit message to update counts
|
||||
let staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** ${ticketData.staff_answers[id] ? ticketData.staff_answers[id].length : 0}`).join("\n");
|
||||
await staffMsg.edit({
|
||||
content: `@here New ticket completed by <@${row.user_id}> in <#${row.channel_id}>.\n\n**Responses:**\n${Object.entries(ticketData.user_answers).map(([index, answer]) => `**Q${parseInt(index) + 1}:** ${config.formData.questions[index]}\n**A:** ${answer}`).join("\n\n")}\n\n${staffResponseCounters}\n\n# Ticket Closed - User Banned`
|
||||
});
|
||||
await staffMsg.components[0].components.forEach(component => {
|
||||
component.disabled = true;
|
||||
});
|
||||
await staffMsg.edit({ components: staffMsg.components });
|
||||
}
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
interaction.guild.channels.cache.get(row.channel_id).delete("Ticket closed - User banned");
|
||||
});
|
||||
return; // Exit to prevent other actions that wouldn't work with this!
|
||||
}).catch(() => { });
|
||||
|
||||
if (acts.kick) return interaction.guild.members.fetch(row.user_id).then(member => {
|
||||
member.kick(acts.kick_reason || "Kicked by staff vote via ticket system.").catch(() => { });
|
||||
// Close ticket processing
|
||||
genTranscript(interaction.guild.channels.cache.get(row.channel_id)).then(async transcript => {
|
||||
if (staffChannel) {
|
||||
await staffChannel.send({ content: `Transcript for ticket by <@${row.user_id}> (kicked):`, files: [{ attachment: Buffer.from(transcript, 'utf-8'), name: `transcript-${interaction.channel.name}.txt` }] });
|
||||
}
|
||||
|
||||
// Update staff msg
|
||||
let staffMsg = await staffChannel.messages.fetch(ticketData.staff_message_id).catch(() => console.error);
|
||||
if (staffMsg) {
|
||||
// Edit message to update counts
|
||||
let staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** ${ticketData.staff_answers[id] ? ticketData.staff_answers[id].length : 0}`).join("\n");
|
||||
await staffMsg.edit({
|
||||
content: `@here New ticket completed by <@${row.user_id}> in <#${row.channel_id}>.\n\n**Responses:**\n${Object.entries(ticketData.user_answers).map(([index, answer]) => `**Q${parseInt(index) + 1}:** ${config.formData.questions[index]}\n**A:** ${answer}`).join("\n\n")}\n\n${staffResponseCounters}\n\n# Ticket Closed - User Kicked`
|
||||
});
|
||||
await staffMsg.components[0].components.forEach(component => {
|
||||
component.disabled = true;
|
||||
});
|
||||
await staffMsg.edit({ components: staffMsg.components });
|
||||
}
|
||||
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
interaction.guild.channels.cache.get(row.channel_id).delete("Ticket closed - User kicked");
|
||||
});
|
||||
}).catch(() => { });
|
||||
}).catch(() => { });
|
||||
|
||||
if (acts.add_roles?.length > 0) {
|
||||
acts.add_roles.forEach(roleId => {
|
||||
console.log("Adding role", roleId, "to user", row.user_id);
|
||||
interaction.guild.members.fetch(row.user_id).then(member => {
|
||||
member.roles.add(roleId).catch(() => { });
|
||||
}).catch(() => { });
|
||||
});
|
||||
}
|
||||
|
||||
if (acts.remove_roles?.length > 0) {
|
||||
acts.remove_roles.forEach(roleId => {
|
||||
console.log("Removing role", roleId, "from user", row.user_id);
|
||||
interaction.guild.members.fetch(row.user_id).then(member => {
|
||||
member.roles.remove(roleId).catch(() => { });
|
||||
}).catch(() => { });
|
||||
});
|
||||
}
|
||||
|
||||
if (acts.close_ticket) return genTranscript(interaction.guild.channels.cache.get(row.channel_id)).then(async transcript => {
|
||||
if (staffChannel) {
|
||||
await staffChannel.send({ content: `Transcript for ticket by <@${row.user_id}> (closed by staff vote):`, files: [{ attachment: Buffer.from(transcript, 'utf-8'), name: `transcript-${interaction.channel.name}.txt` }] });
|
||||
}
|
||||
// Update staff msg
|
||||
let staffMsg = await staffChannel.messages.fetch(ticketData.staff_message_id).catch(() => console.error);
|
||||
if (staffMsg) {
|
||||
// Edit message to update counts
|
||||
let staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** ${ticketData.staff_answers[id] ? ticketData.staff_answers[id].length : 0}`).join("\n");
|
||||
await staffMsg.edit({
|
||||
content: `@here New ticket completed by <@${row.user_id}> in <#${row.channel_id}>.\n\n**Responses:**\n${Object.entries(ticketData.user_answers).map(([index, answer]) => `**Q${parseInt(index) + 1}:** ${config.formData.questions[index]}\n**A:** ${answer}`).join("\n\n")}\n\n${staffResponseCounters}\n\n# Ticket Closed`
|
||||
});
|
||||
await staffMsg.components[0].components.forEach(component => {
|
||||
component.disabled = true;
|
||||
});
|
||||
await staffMsg.edit({ components: staffMsg.components });
|
||||
}
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
interaction.guild.channels.cache.get(row.channel_id).delete("Ticket closed by staff vote");
|
||||
});
|
||||
}).catch(() => { });
|
||||
}
|
||||
};
|
||||
let staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** 0`).join("\n");
|
||||
let staffMsg = await staffChannel.messages.fetch(ticketData.staff_message_id).catch(() => console.error);
|
||||
if (staffMsg) {
|
||||
// Edit message to update counts
|
||||
staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** ${ticketData.staff_answers[id] ? ticketData.staff_answers[id].length : 0}`).join("\n");
|
||||
await staffMsg.edit({
|
||||
content: `@here New ticket completed by <@${row.user_id}> in <#${row.channel_id}>.\n\n**Responses:**\n${Object.entries(ticketData.user_answers).map(([index, answer]) => `**Q${parseInt(index) + 1}:** ${config.formData.questions[index]}\n**A:** ${answer}`).join("\n\n")}\n\n${staffResponseCounters}`
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await interaction.reply({ content: "This ticket is no longer valid.", flags: [MessageFlags.Ephemeral] }).then(() => {
|
||||
setTimeout(() => {
|
||||
interaction.deleteReply().catch(() => { });
|
||||
}, (config.staff_msg_autodelete_time || 30) * 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
client.on('messageCreate', async message => {
|
||||
if (message.author.bot) return;
|
||||
// Check if message is in a ticket channel
|
||||
db.get(`SELECT * FROM tickets WHERE channel_id = ?`, [message.channel.id], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
if (row) {
|
||||
// Verify message author is ticket owner
|
||||
if (message.author.id !== row.user_id) return;
|
||||
|
||||
// It's a ticket channel
|
||||
let ticketData = JSON.parse(row.data);
|
||||
let questionIndex = ticketData.question || 0;
|
||||
if (questionIndex < config.formData.questions.length) {
|
||||
// Save answer
|
||||
ticketData.user_answers[questionIndex] = message.content;
|
||||
questionIndex++;
|
||||
ticketData.question = questionIndex;
|
||||
// Update database
|
||||
db.run(`UPDATE tickets SET data = ? WHERE id = ?`, [JSON.stringify(ticketData), row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
if (questionIndex < config.formData.questions.length) {
|
||||
// Ask next question
|
||||
await message.channel.send({ content: `(${questionIndex + 1 }/${config.formData.questions.length}) ${config.formData.questions[questionIndex]}` });
|
||||
} else {
|
||||
// All questions answered
|
||||
await message.channel.send("Thank you for completing the form! A staff member will be with you shortly.");
|
||||
|
||||
// Generate staff buttons components from config.formData.staff_options
|
||||
let staffButtons = [];
|
||||
for (const [id, option] of Object.entries(config.formData.staff_options)) {
|
||||
staffButtons.push({
|
||||
type: ComponentType.Button,
|
||||
label: option.label,
|
||||
style: option.style,
|
||||
emoji: option.emoji,
|
||||
custom_id: `staff_${message.channel.id}_${id}`
|
||||
});
|
||||
}
|
||||
|
||||
let staffResponseCounters = `**Staff Responses:**\n` + Object.entries(config.formData.staff_options).map(([id, option]) => `**${option.label}:** 0`).join("\n");
|
||||
|
||||
let thisTicketMsg = await staffChannel.send({
|
||||
content: `@here New ticket completed by <@${row.user_id}> in <#${message.channel.id}>.\n\n**Responses:**\n${Object.entries(ticketData.user_answers).map(([index, answer]) => `**Q${parseInt(index) + 1}:** ${config.formData.questions[index]}\n**A:** ${answer}`).join("\n\n")}\n\n${staffResponseCounters}`, components: [
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: staffButtons
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Store msg id in ticket data for future reference
|
||||
ticketData.staff_message_id = thisTicketMsg.id;
|
||||
db.run(`UPDATE tickets SET data = ? WHERE id = ?`, [JSON.stringify(ticketData), row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
client.on('guildMemberRemove', async member => {
|
||||
// Check if member has an open ticket
|
||||
db.get(`SELECT * FROM tickets WHERE user_id = ?`, [member.id], async (err, row) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
if (row) {
|
||||
// Generate transcript and delete channel
|
||||
let transcript = await genTranscript(member.guild.channels.cache.get(row.channel_id));
|
||||
if (staffChannel) {
|
||||
await staffChannel.send({ content: `Transcript for ticket by <@${row.user_id}> (user left):`, files: [{ attachment: Buffer.from(transcript, 'utf-8'), name: `transcript-${member.guild.channels.cache.get(row.channel_id).name}.txt` }] });
|
||||
}
|
||||
// Delete ticket from database
|
||||
db.run(`DELETE FROM tickets WHERE id = ?`, [row.id], async (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
member.guild.channels.cache.get(row.channel_id).delete("Ticket closed - User left the guild");
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
client.login(config.token);
|
||||
Loading…
Reference in a new issue