Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8875c9ff01 | ||
|
|
9b378caff5 | ||
|
|
821a49cb0b | ||
|
|
ebacb92b99 | ||
|
|
e1eb3f252b | ||
|
|
49405b848e | ||
|
|
5dcd36d290 | ||
|
|
d00a26a1e0 | ||
|
|
8c9eddd4a1 | ||
|
|
046cef0088 | ||
|
|
0f143c7ebb | ||
|
|
4cc12eb727 | ||
|
|
e3e5c04096 | ||
|
|
eddbcf9acd | ||
|
|
3c2f39df9c | ||
|
|
ca4532931b | ||
|
|
14ad1f48f3 | ||
|
|
fa8741aef8 | ||
|
|
130fd98d0c | ||
|
|
a9770ec66c | ||
|
|
f163769de4 | ||
|
|
07de112f32 | ||
|
|
8e7a98b810 | ||
|
|
92c1e8fce0 | ||
|
|
4e73626072 | ||
|
|
943e7b6fef | ||
|
|
af8d6351af | ||
|
|
5fc3ba3279 | ||
|
|
6df23d84bc | ||
|
|
8cab4cc686 | ||
|
|
21e3a88b87 | ||
|
|
1451769ebf | ||
|
|
da3017ff95 | ||
|
|
43186c8a0e | ||
|
|
63632e3a66 | ||
|
|
8981c9e60e | ||
|
|
4a90a2d19a | ||
|
|
49b71ecdc6 | ||
|
|
af1c3288c0 | ||
|
|
7d89ac713b |
@@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
package-lock.json
|
||||
devConfig.json
|
||||
.DS_Store
|
||||
@@ -1,69 +1,63 @@
|
||||
# open-ticket
|
||||
This is an open-source discord ticket bot, you can configure it and it comes with cool features like a transcript.
|
||||
[](https://discord.com/invite/26vT9wt3n3) [](https://github.com/DJj123dj/open-ticket/releases/tag/v2.0.0) [](#packages) [](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE)
|
||||
|
||||
(WARNING: the bot's language is Dutch, there will be an English version soon!)
|
||||
This is an open-source discord ticket bot, you can configure it and it comes with cool features like transcripts & custom options!
|
||||
|
||||
<img src="logo.png" alt="Open Ticket logo" style="height: 200px; width:200px;"/>
|
||||
|
||||
[](https://www.github.com/DJj123dj/open-ticket/wiki/q&a)
|
||||
|
||||
## features
|
||||
- discord interaction buttons
|
||||
- slash & text commands
|
||||
- close or delete tickets
|
||||
- translation possible
|
||||
- dynamic database system
|
||||
- transcripts
|
||||
- add/remove users from ticket
|
||||
- custom colors & name
|
||||
- has tickets for questions, partners & job applications
|
||||
- create custom ticket names, icons & colors
|
||||
- create url buttons for websites
|
||||
- uses discord.js 13
|
||||
- configure your own ticket options
|
||||
- remove credits if you want
|
||||
- unlimited tickets at the same time
|
||||
- localisation in +5 languages (soon™)
|
||||
|
||||
## installation
|
||||
You need `node.js 16` to run this project, if you don't want to install `node.js 16` then there is a npm package that can help you.
|
||||
**You need `node.js 16` to run this project!**
|
||||
|
||||
You can clone this project for download.
|
||||
You can clone or download this project.
|
||||
|
||||
### packages
|
||||
- canvas => version `^2.8.0`
|
||||
- discord.js => version `^13.2.0`
|
||||
- express => version `^4.17.1`
|
||||
- node-localstorage => version `^2.2.1`
|
||||
- chalk => version `latest`
|
||||
- discord.js => version `latest`
|
||||
- express => version `latest`
|
||||
- node-localstorage => version `latest`
|
||||
|
||||
The packages are also in package.json!
|
||||
|
||||
### node.js 16 package
|
||||
if you don't want to install `node.js 16`, you can install this package too
|
||||
- node => version ^16.10.0
|
||||
|
||||
_npm install node@16_
|
||||
You can install all of them by running `npm install`
|
||||
|
||||
## running
|
||||
you can run `node index.js` but i would recommend you to use `npm start`
|
||||
|
||||
if there are any errors, you can open an issue on github.
|
||||
if there are any errors, you can open an **issue on github** or **contact me in the discord server**.
|
||||
|
||||
### config (required)
|
||||
- `server_name` => the name from your server.
|
||||
- `server_logo`=> the logo from your server.
|
||||
- `bot_name`=> the bot's name.
|
||||
- `main_color`=> the color used in all embeds.
|
||||
- `auth_token`=> the bot's token (Discord Developer Portal)
|
||||
- `botperms_role`=> the id from a role that can run admin commands with the bot.
|
||||
- `prefix`=> the bot's prefix.
|
||||
|
||||
- `ticket_system/ticket_channel` => the channel where you are gonna put the !ticket msg.
|
||||
- `ticket_system/ticket_category` => the category for tickets.
|
||||
- `ticket_system/member_role` => this role doesn't have access to tickets
|
||||
(WARNING: @everyone does have access to tickets, so make sure all members have a member role!).
|
||||
- `ticket_system/transcript_channel` => the channel for transcripts.
|
||||
- `ticket_system/enable_transcripts` => enable transcripts.
|
||||
- `ticket_system/enable_category` => enable tickets in category.
|
||||
|
||||
- `status/type` => PLAYING | STREAMING | LISTENING | WATCHING | CUSTOM | COMPETING
|
||||
- `status/text` => the status text
|
||||
### config
|
||||
Our config documentation is moved to another file:
|
||||
[click here to view](https://www.github.com/DJj123dj/open-ticket/wiki/config-v2.0.0)
|
||||
|
||||
### intents & permissions
|
||||
In the discord developer portal in the "bot" panel you will find 3 switches under the title "Gateaway Intents". The following switches should always be turned on
|
||||
- `SERVER MEMBERS INTENT`
|
||||
- `MESSAGE CONTENT INTENT`
|
||||
|
||||
The bot needs `ADMINISTRATOR` permissions to work the best.
|
||||
To work the best, the bot needs `ADMINISTRATOR` permissions.
|
||||
You can also configure your own permissions
|
||||
|
||||
## credits
|
||||
the package contains a license, there are also credits in the bot. It is forbidden to extract these licenses and credits from it!
|
||||
## information
|
||||
|
||||
_v1.1.2_
|
||||
_v2.0.0 unstable_
|
||||
|
||||
© 2021 - DJdj Development | [website](https://www.dj-dj.be) | [discord](https://discord.com/invite/26vT9wt3n3)
|
||||
changelog: [click here](https://www.github.com/DJj123dj/open-ticket/wiki/Changelog)
|
||||
|
||||
© 2022 - DJdj Development | [website](https://www.dj-dj.be) | [discord](https://discord.com/invite/26vT9wt3n3)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# documentation
|
||||
The documentation is not available here, go to the [wiki](https://github.com/DJj123dj/open-ticket/wiki) instead. (the wiki isn't fully done yet!)
|
||||
|
||||
## 2.0.0 beta
|
||||
There is currently no documentation available for open-ticket v2.0.0 beta. So if you want to test it, you need to figure it out on yourself at the moment!
|
||||
@@ -0,0 +1,65 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
module.exports = () => {
|
||||
client.on("messageCreate",msg => {
|
||||
if (!msg.content.startsWith(config.prefix+"add")) return
|
||||
var user = msg.mentions.users.first()
|
||||
if (!user){
|
||||
return msg.channel.send({content:"**There is no user to add:**\nuse: `"+config.prefix+"add <user>`"})
|
||||
}
|
||||
|
||||
if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR")){
|
||||
return msg.channel.send({content:"You have no permissions to add someone to the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"})
|
||||
}
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
msg.channel.send({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
msg.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true})
|
||||
msg.channel.send({content:"Added "+user.tag+" to the ticket"})
|
||||
if (config.logs){console.log("[system] added user to ticket (name:"+user.username+",ticket:"+msg.channel.name+")")}
|
||||
|
||||
var loguser = msg.mentions.users.first()
|
||||
if (config.logs){console.log("[command] "+config.prefix+"add "+loguser.username+" (user:"+msg.author.username+")")}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "add") return
|
||||
const user = interaction.options.getUser("user")
|
||||
const member = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id)
|
||||
|
||||
if (!member.permissions.has("MANAGE_CHANNELS") && !member.permissions.has("ADMINISTRATOR")){
|
||||
return interaction.reply({content:"You have no permissions to add someone to the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"})
|
||||
}
|
||||
|
||||
|
||||
interaction.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
interaction.reply({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
interaction.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true})
|
||||
interaction.reply({content:"Added "+user.tag+" to the ticket"})
|
||||
if (config.logs){console.log("[system] added user to ticket (name:"+user.username+",ticket:"+interaction.channel.name+")")}
|
||||
|
||||
var loguser = user
|
||||
if (config.logs){console.log("[command] "+config.prefix+"add "+loguser.username+" (user:"+interaction.user.username+")")}
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
module.exports = () => {
|
||||
client.on("messageCreate",msg => {
|
||||
if (!msg.content.startsWith(config.prefix+"close")) return
|
||||
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
msg.channel.send({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
const closebutton = new discord.MessageActionRow()
|
||||
.addComponents([
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketTrue1")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("🔒")
|
||||
])
|
||||
|
||||
msg.channel.send({content:"**Click on the button below to close this ticket!**",components:[closebutton]})
|
||||
|
||||
console.log("[system] closed a ticket via command")
|
||||
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "close") return
|
||||
|
||||
interaction.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
interaction.reply({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
const closebutton = new discord.MessageActionRow()
|
||||
.addComponents([
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketTrue1")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("🔒")
|
||||
])
|
||||
|
||||
interaction.reply({content:"**Click on the button below to close this ticket!**",components:[closebutton]})
|
||||
|
||||
console.log("[system] closed a ticket via command")
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
module.exports = () => {
|
||||
client.on("messageCreate",msg => {
|
||||
if (!msg.content.startsWith(config.prefix+"delete")) return
|
||||
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
msg.channel.send({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
const closebutton = new discord.MessageActionRow()
|
||||
.addComponents([
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicketTrue")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❌")
|
||||
])
|
||||
|
||||
msg.channel.send({content:"**Click on the button below to delete this ticket!**",components:[closebutton]})
|
||||
|
||||
console.log("[system] deleted a ticket via command")
|
||||
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "delete") return
|
||||
|
||||
interaction.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
interaction.reply({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
const closebutton = new discord.MessageActionRow()
|
||||
.addComponents([
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicketTrue")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❌")
|
||||
])
|
||||
|
||||
interaction.reply({content:"**Click on the button below to delete this ticket!**",components:[closebutton]})
|
||||
|
||||
console.log("[system] deleted a ticket via command")
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
module.exports = () => {
|
||||
const helpEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setTitle("Help Menu:")
|
||||
|
||||
const prefix = config.prefix
|
||||
const header = config.system.ticket_channel ? "**Go to <#"+config.system.ticket_channel+"> to create a ticket!**\n\n" : "**Run the command `/new` or `/ticket` to create a ticket!**\n\n"
|
||||
helpEmbed.setDescription(header+"`"+prefix+"msg <id>` ➜ _Spawn an embed with buttons. (admin only)_\n\n`"+prefix+"rename <name>` ➜ _Rename a ticket. (no spaces)_\n`"+prefix+"close` ➜ _Close a ticket._\n`"+prefix+"delete` ➜ _Delete a ticket._\n\n`"+prefix+"add <user>` ➜ _Add a user to the ticket._\n`"+prefix+"remove <user>` ➜ _Remove a user from the ticket._`")
|
||||
|
||||
if (config.credits) helpEmbed.setFooter({text:"Open-Ticket by DJdj Development | view on github for source code"})
|
||||
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
if (!msg.content.startsWith(config.prefix)) return
|
||||
var args = msg.content.split(config.prefix)
|
||||
|
||||
if (!args[1].startsWith("close") && !args[1].startsWith("delete") && !args[1].startsWith("remove") && !args[1].startsWith("add") && !args[1].startsWith("msg") && !args[1].startsWith("remove") && !args[1].startsWith("rename")){
|
||||
|
||||
msg.channel.send({embeds:[helpEmbed]})
|
||||
if (config.logs){console.log("[command] "+config.prefix+"ticket help (user:"+msg.author.username+")")}
|
||||
}
|
||||
})
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "help") return
|
||||
|
||||
interaction.reply({embeds:[helpEmbed]})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
module.exports = () => {
|
||||
client.on("messageCreate",msg => {
|
||||
if (!msg.content.startsWith(config.prefix+"remove")) return
|
||||
var user = msg.mentions.users.first()
|
||||
if (!user){
|
||||
return msg.channel.send({content:"**There is no user to remove:**\nuse: `"+config.prefix+"remove <user>`"})
|
||||
}
|
||||
|
||||
if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR")){
|
||||
return msg.channel.send({content:"You have no permissions to remove someone from the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"})
|
||||
}
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
msg.channel.send({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
msg.channel.permissionOverwrites.delete(user.id)
|
||||
msg.channel.send({content:"Deleted "+user.tag+" from the ticket"})
|
||||
if (config.logs){console.log("[system] deleted user from ticket (name:"+user.username+",ticket:"+msg.channel.name+")")}
|
||||
|
||||
var loguser = msg.mentions.users.first()
|
||||
if (config.logs){console.log("[command] "+config.prefix+"remove "+loguser.username+" (user:"+msg.author.username+")")}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "remove") return
|
||||
const user = interaction.options.getUser("user")
|
||||
const member = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id)
|
||||
|
||||
if (!member.permissions.has("MANAGE_CHANNELS") && !member.permissions.has("ADMINISTRATOR")){
|
||||
return interaction.reply({content:"You have no permissions to remove someone from the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"})
|
||||
}
|
||||
|
||||
|
||||
interaction.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
interaction.reply({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
interaction.channel.permissionOverwrites.delete(user.id)
|
||||
interaction.reply({content:"Deleted "+user.tag+" from the ticket"})
|
||||
if (config.logs){console.log("[system] removed user from ticket (name:"+user.username+",ticket:"+interaction.channel.name+")")}
|
||||
|
||||
var loguser = user
|
||||
if (config.logs){console.log("[command] "+config.prefix+"remove "+loguser.username+" (user:"+interaction.user.username+")")}
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
module.exports = () => {
|
||||
client.on("messageCreate",msg => {
|
||||
if (!msg.content.startsWith(config.prefix+"rename")) return
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
msg.channel.send({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR")){
|
||||
return msg.channel.send({content:"You have no permissions to change the channel name!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"})
|
||||
}
|
||||
|
||||
var newname = msg.content.split(config.prefix+"rename")[1].substring(1)
|
||||
var name = msg.channel.name
|
||||
var prefix = ""
|
||||
const tickets = config.options
|
||||
tickets.forEach((ticket) => {
|
||||
if (name.startsWith(ticket.channelprefix)){
|
||||
prefix = ticket.channelprefix
|
||||
}
|
||||
})
|
||||
|
||||
if (!prefix) prefix = "noprefix-"
|
||||
|
||||
msg.channel.setName(prefix+newname)
|
||||
msg.channel.send({content:"**The name is changed!**\nWarning: you can only change the channel name 2 times per minute! (this is due discord rate limits)"})
|
||||
|
||||
console.log("[system] renamed a ticket via command")
|
||||
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "rename") return
|
||||
|
||||
interaction.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined || firstmsg.author.id != client.user.id){
|
||||
interaction.reply({content:"You are not in a ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
const member = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id)
|
||||
if (!member.permissions.has("MANAGE_CHANNELS") && !member.permissions.has("ADMINISTRATOR")){
|
||||
return interaction.reply({content:"You have no permissions to change the channel name!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"})
|
||||
}
|
||||
|
||||
var newname = interaction.options.getString("name")
|
||||
var name = interaction.channel.name
|
||||
var prefix = ""
|
||||
const tickets = config.options
|
||||
tickets.forEach((ticket) => {
|
||||
if (name.startsWith(ticket.channelprefix)){
|
||||
prefix = ticket.channelprefix
|
||||
}
|
||||
})
|
||||
|
||||
if (!prefix) prefix = "noprefix-"
|
||||
|
||||
interaction.channel.setName(prefix+newname)
|
||||
interaction.reply({content:"**The name is changed!**\nWarning: you can only change the channel name 2 times per minute! (this is due discord rate limits)"})
|
||||
|
||||
console.log("[system] renamed a ticket via command")
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
+44
-34
@@ -1,52 +1,62 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = require("../config.json")
|
||||
|
||||
var name = require('./ticketExtra').name
|
||||
var stringDecoder = require('./ticketSystem').stringDecoder
|
||||
const config = bot.config
|
||||
|
||||
/** =============================
|
||||
** NOT READY YET
|
||||
** =============================*/
|
||||
|
||||
module.exports = () => {
|
||||
/**@type {String[]} */
|
||||
var msgIds = []
|
||||
config.messages.forEach((msg) => {
|
||||
msgIds.push(msg.id)
|
||||
})
|
||||
|
||||
|
||||
client.on("messageCreate", msg => {
|
||||
if (msg.content == config.prefix+"ticket msg"){
|
||||
if (msg.member.roles.cache.has(config.botperms_role) == false && msg.author.id != "779742674932072469"){
|
||||
msg.channel.send({content:"Je hebt geen permissions voor deze command!"})
|
||||
if (msg.content.startsWith(config.prefix+"msg")){
|
||||
if (config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){
|
||||
msg.channel.send({content:"You have no permission to run this command!"})
|
||||
return
|
||||
}
|
||||
|
||||
var ticketButton = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("newTicketVraag")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❓")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("newTicketSolli")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("📝")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("newTicketPartner")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("💼")
|
||||
)
|
||||
const id = msg.content.split(config.prefix+"msg")[1].substring(1) ? msg.content.split(config.prefix+"msg")[1].substring(1) : false
|
||||
|
||||
var ticketEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setDescription("**Maak een ticket:**\nKlik op een van de onderstaande knoppen om een ticket aan te maken.\n\n__kies een categorie:__\n\n❓: **Vragen**\nOverige vragen.\n\n📝: **Sollicitatie**\nDoe een sollicitatie.\n\n💼: **Partner**\nWord partner met ons.\n\n**opgepast: **_u kan maar één ticket tegelijkertijd aanmaken!_")
|
||||
if (!id) return msg.channel.send({content:"**There is no id!**\nUse: `"+config.prefix+"msg <id>`"})
|
||||
if (!msgIds.includes(id)) return msg.channel.send({content:"**Invalid id!**\nChoose from this list:\n_"+msgIds.join("_\n_")+"_"})
|
||||
|
||||
|
||||
const {embed,componentRows} = require("../core/ticketMessageEmbed").createEmbed(id)
|
||||
|
||||
msg.channel.send({embeds:[ticketEmbed],components:[ticketButton]})
|
||||
|
||||
msg.channel.send({embeds:[embed],components:componentRows})
|
||||
|
||||
if (config.logs){console.log("[command] "+config.prefix+"ticket msg (user:"+msg.author.username+")")}
|
||||
if (config.logs){console.log("[system] created ticket message")}
|
||||
}
|
||||
})
|
||||
|
||||
client.on("interactionCreate", (interaction) => {
|
||||
if (!interaction.isCommand()) return
|
||||
if (interaction.commandName != "message") return
|
||||
|
||||
if (config.main_adminroles.some((item)=>{return interaction.guild.members.cache.find((m) => m.id == interaction.member.id).roles.cache.has(item)}) == false){
|
||||
interaction.reply({content:"You have no permission to run this command!"})
|
||||
return
|
||||
}
|
||||
|
||||
const id = interaction.options.getString("id")
|
||||
|
||||
if (!msgIds.includes(id)) return interaction.reply({content:"**Invalid id!**\nChoose from this list:\n_"+msgIds.join("_\n_")+"_"})
|
||||
|
||||
const {embed,componentRows} = require("../core/ticketMessageEmbed").createEmbed(id)
|
||||
|
||||
interaction.reply({content:"The embed is in the message below!"})
|
||||
interaction.channel.send({embeds:[embed],components:componentRows})
|
||||
|
||||
if (config.logs){console.log("[command] "+config.prefix+"ticket msg (user:"+interaction.member.user.username+")")}
|
||||
if (config.logs){console.log("[system] created ticket message")}
|
||||
|
||||
})
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = require("../config.json")
|
||||
var name = "DJdj Development"
|
||||
exports.name = name
|
||||
var stringDecoder = require('./ticketSystem').stringDecoder
|
||||
|
||||
|
||||
|
||||
module.exports = () => {
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"solli"){
|
||||
var SolliMsg = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setDescription("**Hier is de informatie die wij nodig hebben voor een sollicitatie**\n\n**naam:** Je echte naam.\n**leeftijd:** Je leeftijd.\n**discord naam:** Je discord naam + tag (bv:Wumpus#0001).\n**minecraft naam:** Je minecraft naam.\n**waarom wil je staff worden:** De reden waarom je staff wilt worden.\n**+ punten:** Je plus punten.\n**- punten:** Je min punten.\n**Jou of iemand anders:** Waarom zouden we jou aan moeten nemen en niet een andere sollicitant?\n**ervaring:** Wat is je ervaring met MT servers?\n**andere server:** Ben je op dit moment staff op een andere server?\n**online:** Hoeveel uur per dag/week kan je online zijn?\n**functie:** Voor welke functie solliciteert u?")
|
||||
.setTitle("Sollicitatie")
|
||||
|
||||
msg.channel.send({embeds:[SolliMsg]})
|
||||
}
|
||||
})
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"ticket" && (args[1] == undefined ||args[1] == "" ||args[1] == null)){
|
||||
var TicketHelpMsg = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setDescription("**Ga naar <#"+config.ticket_system.ticket_channel+"> om een ticket te maken!**\n\n`!ticket msg` ➜ _Maak een ticket reageer bericht (staff only)._\n`!ticket rename` ➜ _Rename een ticket (geen spaties)._\n`!ticket close` ➜ _Close een ticket._\n`!ticket add <user>` ➜ _Voeg een speler toe aan het ticket._\n`!ticket remove <user>` ➜ _Verwijder een speler van het ticket._\n`!partner` ➜ _De informatie voor partners._\n`!solli` ➜ _De informatie voor solliciteren._")
|
||||
.setTitle("Ticket commands")
|
||||
.setFooter(stringDecoder+name)
|
||||
|
||||
msg.channel.send({embeds:[TicketHelpMsg]})
|
||||
}
|
||||
})
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"partner"){
|
||||
var PartnerMsg = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setDescription("**Hier zijn de doelen die je moet hebben voor een partnership**\n\n**server:** De naam van je server.\n**beschrijving:** Waar gaat je server over?\n**members:** Het aantal members in je server.\n**invite:** Een oneindige invite.\n\n_als wij dit goedkeuren, kan je je 'invite bericht' plaatsen._")
|
||||
.setTitle("Partnership")
|
||||
|
||||
msg.channel.send({embeds:[PartnerMsg]})
|
||||
}
|
||||
})
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"ticket" && args[1] == "close"){
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
var firstmsg = msglist.last()
|
||||
|
||||
if (firstmsg == undefined){
|
||||
msg.channel.send({content:"Ik heb de sluit knop niet gevonden!"})
|
||||
}
|
||||
if (firstmsg.author.id != client.user.id){
|
||||
msg.channel.send({content:"Je bent niet in een ticket!"})
|
||||
return
|
||||
}
|
||||
var CloseMsg = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setDescription("klik [hier]("+firstmsg.url+") om het ticket te sluiten.")
|
||||
.setTitle("Sluit dit ticket:")
|
||||
|
||||
msg.channel.send({embeds:[CloseMsg]})
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"ticket" && args[1] == "rename"){
|
||||
|
||||
if (msg.member.roles.cache.has(config.botperms_role) == false && msg.author.id != "779742674932072469"){
|
||||
msg.channel.send({content:"Je hebt geen permissions voor deze command!"})
|
||||
return
|
||||
}
|
||||
|
||||
var name = args[2]
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
if (msglist.last().author.id == client.user.id){
|
||||
msg.channel.send({content:"De naam is veranderd!"}).then(rmsg => {
|
||||
rmsg.channel.setName(name)
|
||||
})
|
||||
}else{
|
||||
msg.channel.send({content:"Je bent niet in een ticket!"})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"ticket" && args[1] == "add"){
|
||||
|
||||
if (msg.member.roles.cache.has(config.botperms_role) == false && msg.author.id != "779742674932072469"){
|
||||
msg.channel.send({content:"Je hebt geen permissions voor deze command!"})
|
||||
return
|
||||
}
|
||||
|
||||
msg.channel.messages.fetch().then(msglist => {
|
||||
if (msglist.last().author.id != client.user.id){
|
||||
msg.channel.send({content:"Je bent niet in een ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
if (args[2] == null || args[2] == undefined || args[2] == "" || args[2] == false){
|
||||
msg.channel.send({content:"Niet genoeg parameters!"})
|
||||
return
|
||||
}
|
||||
var user = msg.mentions.users.first()
|
||||
if (!user){
|
||||
return
|
||||
}
|
||||
|
||||
msg.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true})
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
client.on("messageCreate",msg => {
|
||||
var args = msg.content.split(" ")
|
||||
if (args[0] == config.prefix+"ticket" && args[1] == "remove"){
|
||||
|
||||
if (msg.member.roles.cache.has(config.botperms_role) == false && msg.author.id != "779742674932072469"){
|
||||
msg.channel.send({content:"Je hebt geen permissions voor deze command!"})
|
||||
return
|
||||
}
|
||||
|
||||
msg.channel.messages.fetchPinned().then(msglist => {
|
||||
if (msglist.last().author.id != client.user.id){
|
||||
msg.channel.send({content:"Je bent niet in een ticket!"})
|
||||
return
|
||||
}
|
||||
|
||||
if (args[2] == null || args[2] == undefined || args[2] == "" || args[2] == false){
|
||||
msg.channel.send({content:"Niet genoeg parameters!"})
|
||||
return
|
||||
}
|
||||
var user = msg.mentions.users.first()
|
||||
if (!user){
|
||||
return
|
||||
}
|
||||
|
||||
msg.channel.permissionOverwrites.delete(user.id)
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = require("../config.json")
|
||||
|
||||
const ticketStorage = bot.TicketStorage
|
||||
const userTicketStorage = bot.userTicketStorage
|
||||
const transcriptStorage = bot.transcriptStorage
|
||||
|
||||
var stringDecoder = "Created By "
|
||||
exports.stringDecoder = stringDecoder
|
||||
|
||||
module.exports = () => {
|
||||
|
||||
var closeButton = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicket")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setLabel("Sluit Ticket")
|
||||
.setEmoji("❌")
|
||||
)
|
||||
|
||||
client.on("interactionCreate",interaction => {
|
||||
|
||||
if (interaction.isButton() == false){
|
||||
return
|
||||
}
|
||||
|
||||
if (interaction.customId == "newTicketVraag"||interaction.customId == "newTicketSolli"||interaction.customId == "newTicketPartner"){
|
||||
|
||||
interaction.deferUpdate()
|
||||
|
||||
if (ticketStorage.getItem(interaction.member.id) == null ||ticketStorage.getItem(interaction.member.id) == "false"){
|
||||
|
||||
try{
|
||||
interaction.member.send("**Je ticket is aangemaakt!**")
|
||||
}
|
||||
catch{console.log("cant send DM to member")}
|
||||
|
||||
|
||||
|
||||
ticketStorage.setItem(interaction.member.id,"true")
|
||||
|
||||
var ticketNumber = interaction.member.user.username
|
||||
|
||||
if (interaction.customId == "newTicketVraag"){
|
||||
var ticketName = "vraag-"+ticketNumber
|
||||
}else if (interaction.customId == "newTicketSolli"){
|
||||
var ticketName = "solli-"+ticketNumber
|
||||
}else if (interaction.customId == "newTicketPartner"){
|
||||
var ticketName = "partner-"+ticketNumber
|
||||
}
|
||||
|
||||
if (config.ticket_system.enable_category){
|
||||
var Category = config.ticket_system.ticket_category
|
||||
}else{var Category = null}
|
||||
|
||||
interaction.guild.channels.create(ticketName,{
|
||||
type:"GUILD_TEXT",
|
||||
parent:Category,
|
||||
permissionOverwrites:[
|
||||
{
|
||||
id:interaction.member.id,
|
||||
type:"member",
|
||||
allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
},
|
||||
{
|
||||
id:config.botperms_role,
|
||||
type:"role",
|
||||
allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
},
|
||||
{
|
||||
id:config.ticket_system.member_role,
|
||||
type:"role",
|
||||
deny:["VIEW_CHANNEL"]
|
||||
}
|
||||
]
|
||||
}).then(tChannel => {
|
||||
userTicketStorage.setItem(tChannel.id,interaction.member.id)
|
||||
|
||||
|
||||
var ticketEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
|
||||
if (interaction.customId == "newTicketVraag"){
|
||||
ticketEmbed.setDescription("**Ticket gemaakt:**\nJe hebt gekozen voor **overige vragen**, zeg alvast maar je vraag, onze staffleden komen u zo helpen.\n\n_Klik op knop hieronder om dit ticket te sluiten_")
|
||||
}else if (interaction.customId == "newTicketSolli"){
|
||||
ticketEmbed.setDescription("**Ticket gemaakt:**\nJe hebt gekozen voor **sollicitatie**, neem maar tijd om u sollicitatie brief voor te bereiden. Met de `!solli` command kan je zien wat je allemaal moet zeggen.\n\n_Klik op knop hieronder om dit ticket te sluiten_")
|
||||
}else if (interaction.customId == "newTicketPartner"){
|
||||
ticketEmbed.setDescription("**Ticket gemaakt:**\nJe hebt gekozen voor **partner**, neem maar tijd om u partner brief voor te bereiden. Met de `!partner` command kan je zien wat de vereisen zijn.\n\n_Klik op knop hieronder om dit ticket te sluiten_")
|
||||
}
|
||||
|
||||
tChannel.send({content:"<@"+interaction.member.id+"> <@&"+config.botperms_role+">",embeds:[ticketEmbed],components:[closeButton]}).then(firstmsg => {
|
||||
firstmsg.pin()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
}else{
|
||||
try {
|
||||
interaction.member.send("**Je hebt al een ticket open!**")
|
||||
}
|
||||
catch{console.log("cant send DM to member")}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
var closeBar = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketTrue")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("✅")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketFalse")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❌")
|
||||
)
|
||||
|
||||
|
||||
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (interaction.isButton() == false){
|
||||
return
|
||||
}
|
||||
if (interaction.customId == "closeTicket"){
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[closeBar]})
|
||||
}
|
||||
})
|
||||
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (interaction.isButton() == false){
|
||||
return
|
||||
}
|
||||
if (interaction.customId == "closeTicketFalse"){
|
||||
interaction.deferUpdate()
|
||||
|
||||
interaction.message.edit({components:[closeButton]})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (interaction.isButton() == false){
|
||||
return
|
||||
}
|
||||
if (interaction.customId == "closeTicketTrue"){
|
||||
interaction.deferUpdate()
|
||||
interaction.channel.messages.fetch().then(messages => {
|
||||
var transcriptArray = []
|
||||
messages.forEach(msg => {
|
||||
if (msg.author.id != client.user.id){
|
||||
transcriptArray.push("["+msg.author.username+"]: "+msg.content)
|
||||
}
|
||||
})
|
||||
var getuserID = userTicketStorage.getItem(interaction.channel.id)
|
||||
var getusernameStep1 = client.users.cache.find(u => u.id === getuserID)
|
||||
if (getusernameStep1 == null || getusernameStep1 == undefined || getusernameStep1 == false || getusernameStep1 == ""){
|
||||
var getuserNAME = ":user niet in database:"
|
||||
}else {
|
||||
var getuserNAME = getusernameStep1.username
|
||||
}
|
||||
|
||||
|
||||
if (config.ticket_system.enable_transcript){
|
||||
var transcript = transcriptArray.reverse().join("\n")
|
||||
transcriptStorage.setItem(interaction.channel.id,transcript)
|
||||
|
||||
var splittedTranscript = [transcript.slice(0,2000)]
|
||||
if (transcript.length > 4000){
|
||||
splittedTranscript.push(transcript.slice(2000,4000))
|
||||
splittedTranscript.push(transcript.slice(4000))
|
||||
}else if (transcript.length > 2000){
|
||||
splittedTranscript.push(transcript.slice(2000))
|
||||
}
|
||||
var transcriptEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setAuthor(interaction.channel.name + " - ticket gemaakt door "+getuserNAME)
|
||||
.setTitle("Er is een nieuw transcript!")
|
||||
.setDescription(splittedTranscript[0])
|
||||
.setFooter("ticket gesloten door "+interaction.member.user.username)
|
||||
|
||||
if (transcript.length > 4000){
|
||||
var transcriptEmbed2 = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setAuthor(interaction.channel.name + " - ticket gemaakt door "+getuserNAME)
|
||||
.setTitle("Deel 2 van het transcript")
|
||||
.setDescription(splittedTranscript[1])
|
||||
.setFooter("ticket gesloten door "+interaction.member.user.username)
|
||||
var transcriptEmbed3 = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setAuthor(interaction.channel.name + " - ticket gemaakt door "+getuserNAME)
|
||||
.setTitle("Deel 3 van het transcript")
|
||||
.setDescription(splittedTranscript[1])
|
||||
.setFooter("ticket gesloten door "+interaction.member.user.username)
|
||||
|
||||
client.channels.cache.find(ch => ch.id == config.ticket_system.transcript_channel).send({embeds:[transcriptEmbed,transcriptEmbed2,transcriptEmbed3]})
|
||||
|
||||
}else if (transcript.length > 2000){
|
||||
var transcriptEmbed2 = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setAuthor(interaction.channel.name + " - ticket gemaakt door "+getuserNAME)
|
||||
.setTitle("Deel 2 van het transcript")
|
||||
.setDescription(splittedTranscript[1])
|
||||
.setFooter("ticket gesloten door "+interaction.member.user.username)
|
||||
|
||||
client.channels.cache.find(ch => ch.id == config.ticket_system.transcript_channel).send({embeds:[transcriptEmbed,transcriptEmbed2]})
|
||||
}else{
|
||||
client.channels.cache.find(ch => ch.id == config.ticket_system.transcript_channel).send({embeds:[transcriptEmbed]})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
interaction.channel.delete()
|
||||
|
||||
|
||||
ticketStorage.setItem(getuserID,"false")
|
||||
|
||||
try {
|
||||
interaction.member.send("**Je ticket is gesloten door "+interaction.member.user.username+"!**")
|
||||
}
|
||||
catch{console.log("cant send DM to member")}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
process.on('unhandledRejection',error => {
|
||||
console.log("ERROR: "+error)
|
||||
})
|
||||
|
||||
}
|
||||
+77
-13
@@ -1,26 +1,90 @@
|
||||
{
|
||||
"server_name":"Ticket Bot Land",
|
||||
"server_logo":"https://www.example.com/another-example/yourlogo.png",
|
||||
"bot_name":"Wumpus",
|
||||
"main_color":"#fffff",
|
||||
"auth_token":"the bot's auth token",
|
||||
"botperms_role":"the id from a role that can do anything with the bot",
|
||||
"prefix":"!",
|
||||
"server_id":"server id (for slash cmds)",
|
||||
"auth_token":"auth token",
|
||||
"main_adminroles":["discord role id"],
|
||||
"prefix":"!ticket ",
|
||||
"logs":true,
|
||||
"languagefile":"english.json (currently not working)",
|
||||
|
||||
"credits":true,
|
||||
"status":{
|
||||
"type":"PLAYING | STREAMING | LISTENING | WATCHING | CUSTOM | COMPETING",
|
||||
"enabled":true,
|
||||
"type":"PLAYING",
|
||||
"text":"!ticket"
|
||||
},
|
||||
|
||||
"ticket_system":{
|
||||
"ticket_channel":"id of the channel with the !ticket msg",
|
||||
"system":{
|
||||
"ticket_channel":"channel id",
|
||||
"max_allowed_tickets":3,
|
||||
"enable_DM_Messages":true,
|
||||
|
||||
"enable_category":false,
|
||||
"ticket_category":"the id of a category for the tickets",
|
||||
|
||||
"member_role":"this role doesn't have access to tickets (WARNING: @everyone does have access to tickets, so make sure all members have a member role!)",
|
||||
"has@everyoneaccess":false,
|
||||
"member_role":"member role (doesn't have access to tickets)",
|
||||
|
||||
"enable_transcript":false,
|
||||
"transcript_channel":"the channel for transcripts"
|
||||
"enable_DM_transcript":false,
|
||||
"transcript_channel":"channel id"
|
||||
},
|
||||
|
||||
"options":[
|
||||
{
|
||||
"id":"general",
|
||||
"name":"Question",
|
||||
"description":"Create this ticket if you have a question.",
|
||||
"icon":"🎫",
|
||||
"label":"question",
|
||||
"type":"ticket",
|
||||
|
||||
"color":"gray",
|
||||
"adminroles":["role id"],
|
||||
"channelprefix":"question-",
|
||||
"category":"category id",
|
||||
"message":"You created a ticket!",
|
||||
"enableDMMessage":true
|
||||
|
||||
},
|
||||
{
|
||||
"id":"website",
|
||||
"name":"Website",
|
||||
"description":"Go to our website.",
|
||||
"icon":"✅",
|
||||
"label":"click here",
|
||||
"type":"website",
|
||||
|
||||
"url":"https://www.dj-dj.be"
|
||||
|
||||
},
|
||||
{
|
||||
"id":"role",
|
||||
"name":"Verify",
|
||||
"description":"Click here to get the verify role.",
|
||||
"icon":"👮🏼",
|
||||
"label":"get a role",
|
||||
"type":"role",
|
||||
|
||||
"color":"red",
|
||||
"roles":["discord role id"],
|
||||
"mode":"add&remove|remove|add",
|
||||
"enableDMMessage":true
|
||||
|
||||
}
|
||||
],
|
||||
|
||||
"messages":[
|
||||
{
|
||||
"id":"1",
|
||||
"name":"Choose Your Ticket",
|
||||
"description":"You can click one of the buttons below!\nYou can also customize all the embeds now!",
|
||||
"enableFooter":true,
|
||||
"footer":"Open Ticket v2.0.0 beta - sneakpeak",
|
||||
"enableThumbnail":false,
|
||||
"thumbnail":"https://www.example.com/catmemes/cat.png",
|
||||
"color":"#0075e9",
|
||||
"options":["general","apply"],
|
||||
"enableTicketExplaination":true,
|
||||
"enableMaxTicketsWarning":true
|
||||
}
|
||||
]
|
||||
}
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
exports.checker = async () => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
const config = require("../config.json")
|
||||
var errorList = []
|
||||
var isError = false
|
||||
var warnList = []
|
||||
var isWarn = false
|
||||
const createError = (message) => {
|
||||
isError = true
|
||||
errorList.push("open-ticket CONFIG ERROR: "+message)
|
||||
}
|
||||
const createWarn = (message) => {
|
||||
isWarn = true
|
||||
warnList.push("open-ticket CONFIG WARNING: "+message)
|
||||
}
|
||||
|
||||
//validators
|
||||
/**@param {"userid"|"roleid"|"channelid"|"serverid"|"categoryid"} mode @param {String} value @param {String} path */
|
||||
const checkDiscord = (mode,value,path) => {
|
||||
if (mode == "userid"){
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+"' | this user id is invalid")
|
||||
}
|
||||
}else if (mode == "channelid"){
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+"' | this channel id is invalid")
|
||||
}
|
||||
}else if (mode == "roleid"){
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+"' | this role id is invalid")
|
||||
}
|
||||
}else if (mode == "serverid"){
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+"' | this server id is invalid")
|
||||
}
|
||||
}else if (mode == "categoryid"){
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+"' | this category id is invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
/**@param {String} value */
|
||||
const checkToken = (value) => {
|
||||
if (value.includes(" ") || value.length < 40 || value.length > 70){
|
||||
createError("'auth_token' | your token is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
/**@param {String} value @param {String} path */
|
||||
const checkColor = (value,path) => {
|
||||
if (!/^#[a-f0-9]{6}$/.test(value)){
|
||||
createError("'"+path+"' | invalid color!")
|
||||
}
|
||||
}
|
||||
|
||||
/**@param {String} value @param {String} path @param {Number} minLength @param {Number} maxLength @param {String} name */
|
||||
const checkString = (value,minLength,maxLength,path,name) => {
|
||||
if (value.length < minLength){
|
||||
createError("'"+path+"' | "+name+" is too short!")
|
||||
}else if (value.length > maxLength){
|
||||
createError("'"+path+"' | "+name+" is too long!")
|
||||
}
|
||||
}
|
||||
|
||||
/**@param {"userid"|"roleid"|"channelid"|"serverid"} mode @param {String[]} arrayValue @param {String} path */
|
||||
const checkDiscordArray = (mode,arrayValue,path) => {
|
||||
if (mode == "userid"){
|
||||
arrayValue.forEach((value,index) => {
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+":"+index+"' | this user id is invalid")
|
||||
}
|
||||
})
|
||||
}else if (mode == "channelid"){
|
||||
arrayValue.forEach((value,index) => {
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+":"+index+"' | this channel id is invalid")
|
||||
}
|
||||
})
|
||||
}else if (mode == "roleid"){
|
||||
arrayValue.forEach((value,index) => {
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+":"+index+"' | this role id is invalid")
|
||||
}
|
||||
})
|
||||
}else if (mode == "serverid"){
|
||||
arrayValue.forEach((value,index) => {
|
||||
if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){
|
||||
createError("'"+path+":"+index+"' | this server id is invalid")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
/**@param {String} value @param {"string"|"boolean"|"number"} type */
|
||||
const checkType = (value,type,path) => {
|
||||
if (type == "boolean"){
|
||||
if (typeof value != "boolean"){
|
||||
createError("'"+path+"' | invalid type, this must be a boolean!")
|
||||
}
|
||||
}else if (type == "number"){
|
||||
if (typeof value != "number"){
|
||||
createError("'"+path+"' | invalid type, this must be a number!")
|
||||
}
|
||||
}else if (type == "string"){
|
||||
if (typeof value != "string"){
|
||||
createError("'"+path+"' | invalid type, this must be a string!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const checkButtonColor = (value,path) => {
|
||||
if (value != "none" && value != "grey" && value != "gray" && value != "black" && value != "red" && value != "green" && value != "blue" && value != "blurple"){
|
||||
createError("'"+path+"' | invalid color, it must be one of these: none, gray, red, green, blue!")
|
||||
}
|
||||
}
|
||||
|
||||
const getButtonClass = require("./utils/getButton").rawButtonData
|
||||
/**@param {getButtonClass} option */
|
||||
const checkOption = (option,path) => {
|
||||
|
||||
//id
|
||||
checkType(option.id,"string",path+"/id")
|
||||
if (option.id.includes(" ")){
|
||||
createError("'"+path+"/id' | option id can't contain space characters!")
|
||||
}
|
||||
if (option.id.length > 20){
|
||||
createError("'"+path+"/id' | option id max lenght is 20")
|
||||
}
|
||||
|
||||
//name
|
||||
checkType(option.name,"string",path+"/name")
|
||||
if (option.name.length > 100){
|
||||
createWarn("'"+path+"/name' | if your name is too long it maybe doesn't look so good!")
|
||||
}
|
||||
|
||||
//description
|
||||
checkType(option.description,"string",path+"/description")
|
||||
|
||||
//icon
|
||||
const emojiRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gi;
|
||||
if (option.icon.length > 0){
|
||||
|
||||
const isEmoji = emojiRegex.test(option.icon)
|
||||
|
||||
if (isEmoji == false){
|
||||
createError("'"+path+"/icon' | invalid emoji or custom discord emoji")
|
||||
}
|
||||
}
|
||||
checkType(option.icon,"string",path+"/icon")
|
||||
|
||||
//label
|
||||
checkType(option.label,"string",path+"/label")
|
||||
if (option.label.length < 1 && option.icon.length < 1){
|
||||
createError("'"+path+"' | you need at least one of these: label, icon!")
|
||||
}
|
||||
|
||||
//type
|
||||
checkType(option.type,"string",path+"/type")
|
||||
if (option.type != "ticket" && option.type != "website" && option.type != "role"){
|
||||
createError("'"+path+"/type' | the type must be one of these: ticket, website, role!")
|
||||
}
|
||||
/**@type {"ticket"|"website"|"role"} */
|
||||
const type = option.type
|
||||
|
||||
if (type == "ticket"){
|
||||
//color
|
||||
checkType(option.color,"string",path+"/color")
|
||||
checkButtonColor(option.color,path+"/color")
|
||||
|
||||
//adminroles
|
||||
checkDiscordArray("roleid",option.adminroles,path+"/adminroles")
|
||||
|
||||
//channelprefix
|
||||
checkType(option.channelprefix,"string",path+"/channelprefix")
|
||||
if (option.channelprefix.includes(" ")){
|
||||
createWarn("'"+path+"/channelprefix' | this prefix can't contain spaces!")
|
||||
}
|
||||
|
||||
//category
|
||||
checkType(option.category,"string",path+"/category")
|
||||
checkDiscord("categoryid",option.category,path+"/category")
|
||||
|
||||
//message
|
||||
checkType(option.message,"string",path+"/message")
|
||||
|
||||
//enableDMmessage
|
||||
checkType(option.enableDMMessage,"boolean",path+"/enableDMMessage")
|
||||
}else if (type == "website"){
|
||||
//url
|
||||
checkType(option.url,"string",path+"/url")
|
||||
if (option.url.includes(" ")){
|
||||
createWarn("'"+path+"/url' | a url can't contain spaces")
|
||||
}
|
||||
if (option.url.length < 1){
|
||||
createError("'"+path+"/url' | you have no url in this button")
|
||||
}
|
||||
if (!option.url.startsWith("https://") && !option.url.startsWith("http://") && !option.url.startsWith("discord://")){
|
||||
createWarn("'"+path+"/url' | your url doesn't start with https or http!")
|
||||
}
|
||||
if (option.url.startsWith("http://")){
|
||||
createWarn("'"+path+"/url' | your url is not a HTTPS link! discord maybe blocks this url!")
|
||||
}
|
||||
}else if (type == "role"){
|
||||
//color
|
||||
checkType(option.color,"string",path+"/color")
|
||||
checkButtonColor(option.color,path+"/color")
|
||||
|
||||
//roles
|
||||
checkDiscordArray("roleid",option.roles,path+"/roles")
|
||||
|
||||
//mode
|
||||
checkType(option.mode,"string",path+"/mode")
|
||||
if (option.mode != "add&remove" && option.mode != "add" && option.mode != "remove"){
|
||||
createError("'"+path+"/mode' | mode must be one of these: add, remove, add&remove")
|
||||
}
|
||||
|
||||
//enableDMmessage
|
||||
checkType(option.enableDMMessage,"boolean",path+"/enableDMMessage")
|
||||
}
|
||||
}
|
||||
|
||||
//checker
|
||||
var configArray = ["bot_name","main_color","server_id","auth_token","main_adminroles","prefix","logs","languagefile","credits","status","system","options","messages"]
|
||||
configArray.forEach((item) => {
|
||||
if (config[item] == undefined){
|
||||
throw new Error("\n\nMAIN ERROR: the item '"+item+"' doesn't exist in config.json")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
checkType(config.bot_name,"string","bot_name")
|
||||
checkColor(config.main_color,"main_color")
|
||||
checkDiscord("serverid",config.server_id,"server_id")
|
||||
checkToken(config.auth_token)
|
||||
checkDiscordArray("roleid",config.main_adminroles,"main_adminroles")
|
||||
checkString(config.prefix,1,15,"prefix","prefix")
|
||||
checkType(config.logs,"boolean","logs")
|
||||
//languagefile (comming soon)
|
||||
|
||||
|
||||
checkType(config.credits,"boolean","credits")
|
||||
//status:
|
||||
checkType(config.status.enabled,"boolean","status/enabled")
|
||||
if (config.status.enabled){
|
||||
if (config.status.type != "PLAYING" && config.status.type != "LISTENING" && config.status.type != "WATCHING"){
|
||||
createError("'status/type' | not a valid status type!")
|
||||
}
|
||||
if (config.status.text.length < 1 || config.status.text.length > 40){
|
||||
createError("'status/text' | text too long or short!")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//system:
|
||||
if (config.system.ticket_channel){
|
||||
if (config.system.ticket_channel.length < 16 || config.system.ticket_channel.length > 20 || !/^\d+$/.test(config.system.ticket_channel)){
|
||||
createError("'system/ticket_channel' | this channel id is invalid")
|
||||
}
|
||||
}else createWarn("'"+path+"' | you have no ticket channel selected!")
|
||||
checkType(config.system.max_allowed_tickets,"number","system/max_allowed_tickets")
|
||||
checkType(config.system.enable_DM_Messages,"boolean","system/enable_DM_Messages")
|
||||
checkType(config.system["has@everyoneaccess"],"boolean","system/has@everyoneaccess")
|
||||
if (config.system.member_role != "" && config.system.member_role != " " && config.system.member_role != "false" && config.system.member_role != "null" && config.system.member_role != "0"){
|
||||
checkDiscord("roleid",config.system.member_role,"system/member_role")
|
||||
}
|
||||
checkType(config.system.enable_transcript,"boolean","system/enable_transcript")
|
||||
checkType(config.system.enable_DM_transcript,"boolean","system/enable_DM_transcript")
|
||||
if (config.system.enable_transcript){
|
||||
checkDiscord("channelid",config.system.transcript_channel,"system/transcript_channel")
|
||||
}
|
||||
|
||||
//options
|
||||
|
||||
config.options.forEach((option,index) => {
|
||||
checkOption(option,"options/"+index)
|
||||
})
|
||||
|
||||
|
||||
|
||||
//the end
|
||||
if (errorList.length > 0 || warnList.length > 0){
|
||||
console.log("REPORT:\n===========================")
|
||||
}
|
||||
warnList.forEach((w) => {
|
||||
const splitw = w.split("'")
|
||||
if (splitw.length > 1){
|
||||
var splitstring = chalk.yellow(splitw[0])+chalk.blue("'"+splitw[1]+"'")+chalk.yellow(splitw[2])
|
||||
}else {var splitstring = chalk.yellow(splitw[0])}
|
||||
console.log(splitstring)
|
||||
})
|
||||
errorList.forEach((e) => {
|
||||
const splite = e.split("'")
|
||||
if (splite.length > 1){
|
||||
var splitstring = chalk.red(splite[0])+chalk.blue("'"+splite[1]+"'")+chalk.red(splite[2])
|
||||
}else {var splitstring = chalk.red(splite[0])}
|
||||
console.log(splitstring)
|
||||
})
|
||||
if (isError){
|
||||
console.log("===========================")
|
||||
console.log("=> "+chalk.bgRed("your bot doesn't work if you don't fix the above errors!"))
|
||||
if (isWarn){
|
||||
console.log("\n=> "+chalk.bgYellow("if you ignore warns, some things may work differently than expected!"))
|
||||
}
|
||||
process.exit(0)
|
||||
}else if (isWarn == true && isError == false){
|
||||
console.log("===========================")
|
||||
console.log("=> "+chalk.bgYellow("if you ignore warns, some things may work differently than expected!"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.checker()
|
||||
@@ -0,0 +1,236 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
|
||||
module.exports = () => {
|
||||
//closebar
|
||||
var closeBar = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketTrue")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("✅")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketFalse")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❌")
|
||||
)
|
||||
var deleteBar = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicketTrue")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("✅")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicketFalse")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❌")
|
||||
)
|
||||
var deleteBar1 = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicketTrue1")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("✅")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicketFalse1")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("❌")
|
||||
)
|
||||
//closebutton
|
||||
var closeRowNormal = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicket")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setLabel("Close Ticket")
|
||||
.setEmoji("🔒")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicket")
|
||||
.setDisabled(false)
|
||||
.setStyle("DANGER")
|
||||
.setLabel("Delete Ticket")
|
||||
.setEmoji("✖️")
|
||||
)
|
||||
var closeRowClosed = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicket1")
|
||||
.setDisabled(false)
|
||||
.setStyle("DANGER")
|
||||
.setLabel("Delete Ticket")
|
||||
.setEmoji("✖️")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("sendTranscript")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setLabel("Send Transcript File")
|
||||
.setEmoji("📄")
|
||||
)
|
||||
|
||||
|
||||
//NORMAL CLOSE
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "closeTicket") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[closeBar]})
|
||||
|
||||
})
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "closeTicketFalse") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[closeRowNormal]})
|
||||
})
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "closeTicketTrue") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[closeRowClosed]})
|
||||
|
||||
/**
|
||||
* @type {String}
|
||||
*/
|
||||
const name = interaction.channel.name
|
||||
var prefix = ""
|
||||
const tickets = config.options
|
||||
tickets.forEach((ticket) => {
|
||||
if (name.startsWith(ticket.channelprefix)){
|
||||
prefix = ticket.channelprefix
|
||||
}
|
||||
})
|
||||
|
||||
require("./ticketCloser").closeTicket(interaction,prefix,"close")
|
||||
})
|
||||
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "closeTicketTrue1") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
const closedButtonDisabled = new discord.MessageActionRow()
|
||||
.addComponents([
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicketTrue1")
|
||||
.setDisabled(true)
|
||||
.setStyle("SECONDARY")
|
||||
.setEmoji("🔒")
|
||||
])
|
||||
interaction.message.edit({components:[closedButtonDisabled]})
|
||||
|
||||
/**
|
||||
* @type {String}
|
||||
*/
|
||||
const name = interaction.channel.name
|
||||
var prefix = ""
|
||||
const tickets = config.options
|
||||
tickets.forEach((ticket) => {
|
||||
if (name.startsWith(ticket.channelprefix)){
|
||||
prefix = ticket.channelprefix
|
||||
}
|
||||
})
|
||||
|
||||
require("./ticketCloser").closeTicket(interaction,prefix,"close")
|
||||
})
|
||||
|
||||
|
||||
//NORMAL DELETE
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "deleteTicket") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[deleteBar]})
|
||||
|
||||
})
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "deleteTicketFalse") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[closeRowNormal]})
|
||||
})
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "deleteTicketTrue") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
|
||||
/**
|
||||
* @type {String}
|
||||
*/
|
||||
const name = interaction.channel.name
|
||||
var prefix = ""
|
||||
const tickets = config.options
|
||||
tickets.forEach((ticket) => {
|
||||
if (name.startsWith(ticket.channelprefix)){
|
||||
prefix = ticket.channelprefix
|
||||
}
|
||||
})
|
||||
|
||||
require("./ticketCloser").closeTicket(interaction,prefix,"delete")
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
//CLOSED DELETE
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "deleteTicket1") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[deleteBar1]})
|
||||
|
||||
})
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "deleteTicketFalse1") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
interaction.message.edit({components:[closeRowClosed]})
|
||||
})
|
||||
client.on("interactionCreate",interaction => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "deleteTicketTrue1") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
|
||||
/**
|
||||
* @type {String}
|
||||
*/
|
||||
const name = interaction.channel.name
|
||||
var prefix = ""
|
||||
const tickets = config.options
|
||||
tickets.forEach((ticket) => {
|
||||
if (name.startsWith(ticket.channelprefix)){
|
||||
prefix = ticket.channelprefix
|
||||
}
|
||||
})
|
||||
|
||||
require("./ticketCloser").closeTicket(interaction,prefix,"deletenotranscript")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
const fs = require('fs')
|
||||
const readline = require("readline")
|
||||
const rl = readline.createInterface({
|
||||
input:process.stdin,
|
||||
output:process.stdout,
|
||||
terminal:true
|
||||
})
|
||||
|
||||
const ask = async () => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
rl.question(chalk.yellow("WARNING: are you sure that there are",chalk.red("no tickets open"),"at the moment? ")+chalk.green("(yes/no)")+"\n",(answer) => {
|
||||
if (answer != "1" && !answer.toLowerCase().startsWith("yes")){
|
||||
console.log(chalk.red("invalid answer"))
|
||||
ask()
|
||||
return
|
||||
}
|
||||
console.log(chalk.green("clearing data..."))
|
||||
runClear()
|
||||
rl.close()
|
||||
})
|
||||
}
|
||||
ask()
|
||||
|
||||
const runClear = async () => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
console.log(chalk.blue("You can get a node.js warning below, just ignore that, it's not important!"))
|
||||
const dataPaths = ["./storage/dynamicDB"]
|
||||
|
||||
var index = 0
|
||||
|
||||
dataPaths.forEach((path) => {
|
||||
try {
|
||||
fs.rmdirSync(path,{recursive:true,force:true})
|
||||
}catch{
|
||||
//console.log(path,"doesn't exist")
|
||||
}
|
||||
setTimeout(() => {
|
||||
try{
|
||||
fs.mkdirSync(path)
|
||||
}catch{
|
||||
//console.log(path,"already exists")
|
||||
}
|
||||
index++
|
||||
},500)
|
||||
})
|
||||
|
||||
setInterval(() => {
|
||||
if (index >= 1){
|
||||
console.log(chalk.bgGreen("All local data is cleared!"))
|
||||
process.exit(1)
|
||||
}
|
||||
},500)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
const localstorage = require("node-localstorage")
|
||||
|
||||
const ls = new localstorage.LocalStorage("./storage/dynamicDB")
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} category
|
||||
* @param {String} id
|
||||
* @param {String} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
exports.set = (category,id,value) => {
|
||||
ls.setItem(category+"--"+id,value.toString())
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} category
|
||||
* @param {String} id
|
||||
* @returns {String|false}
|
||||
*/
|
||||
exports.get = (category,id) => {
|
||||
const result = ls.getItem(category+"--"+id)
|
||||
if (!result) return false
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} category
|
||||
* @param {String} id
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
exports.delete = (category,id) => {
|
||||
ls.removeItem(category+"--"+id)
|
||||
return true
|
||||
}
|
||||
@@ -1,3 +1,22 @@
|
||||
//Do not change this without knowing what you are doing!!
|
||||
const databaseFile = "local"
|
||||
//Do not change this without knowing what you are doing!!
|
||||
|
||||
|
||||
try {
|
||||
var db = require("./dynamicfiles/local")
|
||||
}catch{
|
||||
console.log("I couldn't find the database file! (location: ./core/dynamicdatabase/storage.js:2)")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
module.exports = db
|
||||
|
||||
|
||||
/** =============================
|
||||
** NOT READY YET
|
||||
** must be dynamic
|
||||
** =============================*/
|
||||
const LocalStorage = require("node-localstorage")
|
||||
|
||||
const ticketStorage = new LocalStorage.LocalStorage("./storage/tickets")
|
||||
@@ -0,0 +1,114 @@
|
||||
const bot = require("../index")
|
||||
const config = bot.config
|
||||
|
||||
/**
|
||||
* @param {Number} index
|
||||
* @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDMMessage"} value
|
||||
*/
|
||||
exports.getTicketValue = (index,value) => {
|
||||
if (value == "id"){
|
||||
return "newT"+config.options[index][value]
|
||||
}
|
||||
return config.options[index][value]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} index
|
||||
* @param {"id"|"name"|"description"|"icon"|"label"|"type"|"url"} value
|
||||
*/
|
||||
exports.getWebsiteValue = (index,value) => {
|
||||
return config.options[index][value]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} index
|
||||
* @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"roles"|"mode"|"enableDMMessage"} value
|
||||
*/
|
||||
exports.getRoleValue = (index,value) => {
|
||||
return config.options[index][value]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDMMessage"} value
|
||||
*/
|
||||
exports.getTicketValues = (value) => {
|
||||
var result = []
|
||||
config.options.forEach((o) => {
|
||||
if (value == "id"){
|
||||
result.push("newT"+o[value])
|
||||
}else{
|
||||
result.push(o[value])
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {"id"|"name"|"description"|"icon"|"label"|"type"|"url"} value
|
||||
*/
|
||||
exports.getWebsiteValues = (value) => {
|
||||
var result = []
|
||||
config.options.forEach((o) => {
|
||||
result.push(o[value])
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"roles"|"mode"|"enableDMMessage"} value
|
||||
*/
|
||||
exports.getRoleValues = (value) => {
|
||||
var result = []
|
||||
config.options.forEach((o) => {
|
||||
result.push(o[value])
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
class TicketOptions {
|
||||
constructor() {
|
||||
this.id = ""
|
||||
this.name = ""
|
||||
this.description = ""
|
||||
this.icon = ""
|
||||
this.label = ""
|
||||
this.type = ""
|
||||
this.color = ""
|
||||
this.adminroles = ["",""]
|
||||
this.channelprefix = ""
|
||||
this.category = ""
|
||||
this.message = ""
|
||||
this.enableDMMessage = true
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {String} id
|
||||
* @returns {TicketOptions|false}
|
||||
*/
|
||||
exports.getOptionsById = (id) => {
|
||||
var result = false
|
||||
config.options.forEach((option) => {
|
||||
if ("newT"+option.id == id){
|
||||
result = option
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
exports.exportedOptionClass = class {
|
||||
constructor() {
|
||||
this.id = ""
|
||||
this.name = ""
|
||||
this.description = ""
|
||||
this.icon = ""
|
||||
this.label = ""
|
||||
this.type = ""
|
||||
this.color = ""
|
||||
this.adminroles = ["",""]
|
||||
this.channelprefix = ""
|
||||
this.category = ""
|
||||
this.message = ""
|
||||
this.enableDMMessage = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
const storage = bot.storage
|
||||
|
||||
module.exports = async () => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isButton()) return
|
||||
if (!interaction.customId.startsWith("newR")) return
|
||||
|
||||
interaction.deferUpdate()
|
||||
|
||||
const optionid = interaction.customId.split("newR")[1]
|
||||
if (!optionid){
|
||||
interaction.reply({content:"This button doesn't exist anymore"})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const option = require("./utils/getButton").getOption(optionid)
|
||||
/**@type {"add"|"remove"|"add&remove"} */
|
||||
const mode = option.mode
|
||||
const user = interaction.member
|
||||
|
||||
if (mode == "add"){
|
||||
option.roles.forEach((role) => {
|
||||
interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role)
|
||||
console.log("[system] added role",role,"to",user.user.tag)
|
||||
})
|
||||
}else if (mode == "remove"){
|
||||
option.roles.forEach((role) => {
|
||||
interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role)
|
||||
console.log("[system] removed role",role,"from",user.user.tag)
|
||||
})
|
||||
}else if (mode == "add&remove"){
|
||||
option.roles.forEach((role) => {
|
||||
if (interaction.guild.members.cache.find(u => u.id == user.id).roles.cache.has(role)){
|
||||
interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role)
|
||||
console.log("[system] removed role",role,"from",user.user.tag)
|
||||
}else {
|
||||
interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role)
|
||||
console.log("[system] added role",role,"to",user.user.tag)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}catch{
|
||||
interaction.reply({ephemeral:true,content:"Something went wrong! Contact the owner of this bot for more information"})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
const discord = require("discord.js")
|
||||
const bot = require("../../index")
|
||||
const client = require("../../index").client
|
||||
const config = bot.config
|
||||
const getoptions = require("../getoptions")
|
||||
|
||||
module.exports = async () => {
|
||||
const chalk = (await import("chalk")).default
|
||||
|
||||
console.log(chalk.red("\nINSTRUCTIONS:\n\n1: Run the command you want to delete in discord.\n2: You get the message 'This command is now deleted!'\n3: There is also a message in the console that says the command is deleted.\n4: reload your discord."))
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (!interaction.isCommand()) return console.log("this isn't a command!")
|
||||
|
||||
interaction.reply({content:"This command is now deleted!"})
|
||||
|
||||
try {
|
||||
client.application.commands.delete(interaction.commandId,interaction.guild.id).then(() => {
|
||||
console.log("deleted the command",chalk.blue(interaction.commandName),"(id:",interaction.commandId+")")
|
||||
})
|
||||
}catch{
|
||||
console.log(chalk.red("something went wrong by the deleting of this command!"))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
const discord = require("discord.js")
|
||||
const bot = require("../../index")
|
||||
const client = require("../../index").client
|
||||
const config = bot.config
|
||||
const getoptions = require("../getoptions")
|
||||
|
||||
module.exports = async () => {
|
||||
const chalk = (await import("chalk")).default
|
||||
const sid = config.server_id
|
||||
|
||||
const ids = getoptions.getTicketValues("id")
|
||||
/**@type {[{name:String,value:String}]} */
|
||||
var choices = []
|
||||
ids.forEach((id) => {
|
||||
const option = getoptions.getOptionsById(id)
|
||||
choices.push({name:option.name,value:option.id})
|
||||
})
|
||||
|
||||
/**@type {[{name:String,value:String}]} */
|
||||
var msgchoices = []
|
||||
config.messages.forEach((msg) => {
|
||||
msgchoices.push({name:msg.id,value:msg.id})
|
||||
})
|
||||
|
||||
var readystats = 0
|
||||
|
||||
process.stdout.write("[status] there are "+chalk.blue("0 out of 9")+" commands ready! (this can take up to 40 seconds)")
|
||||
setInterval(() => {
|
||||
process.stdout.cursorTo(0)
|
||||
process.stdout.write("[status] there are "+chalk.blue(readystats+" out of 9")+" commands ready! (this can take up to 40 seconds)")
|
||||
if (readystats >= 9){
|
||||
console.log(chalk.green("\nready!"))
|
||||
console.log(chalk.bgBlue("you can now start the bot with 'npm start'!"))
|
||||
process.exit(1)
|
||||
}
|
||||
},100)
|
||||
|
||||
//create a ticket (/new or /ticket)
|
||||
client.application.commands.create({
|
||||
name:"ticket",
|
||||
description:"Create a ticket!",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT",
|
||||
options:[
|
||||
{
|
||||
type:"STRING",
|
||||
name:"type",
|
||||
description:"The type of ticket.",
|
||||
required:true,
|
||||
choices:choices
|
||||
|
||||
}
|
||||
]
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
client.application.commands.create({
|
||||
name:"new",
|
||||
description:"Create a ticket!",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT",
|
||||
options:[
|
||||
{
|
||||
type:"STRING",
|
||||
name:"type",
|
||||
description:"The type of ticket.",
|
||||
required:true,
|
||||
choices:choices
|
||||
|
||||
}
|
||||
]
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
//help
|
||||
client.application.commands.create({
|
||||
name:"help",
|
||||
description:"The help menu",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT"
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
|
||||
})
|
||||
|
||||
//close
|
||||
client.application.commands.create({
|
||||
name:"close",
|
||||
description:"Close the current ticket.",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT"
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
//delete
|
||||
client.application.commands.create({
|
||||
name:"delete",
|
||||
description:"Delete the current ticket.",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT"
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
//msg
|
||||
client.application.commands.create({
|
||||
name:"message",
|
||||
description:"Create a ticket message.",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT",
|
||||
options:[
|
||||
{
|
||||
type:"STRING",
|
||||
name:"id",
|
||||
description:"The message id.",
|
||||
required:true,
|
||||
choices:msgchoices
|
||||
|
||||
}
|
||||
]
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
//add
|
||||
client.application.commands.create({
|
||||
name:"add",
|
||||
description:"Add people to this ticket.",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT",
|
||||
options:[
|
||||
{
|
||||
type:"USER",
|
||||
name:"user",
|
||||
description:"The user to add.",
|
||||
required:true
|
||||
}
|
||||
]
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
//remove
|
||||
client.application.commands.create({
|
||||
name:"remove",
|
||||
description:"Remove people from this ticket.",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT",
|
||||
options:[
|
||||
{
|
||||
type:"USER",
|
||||
name:"user",
|
||||
description:"The user to remove.",
|
||||
required:true
|
||||
}
|
||||
]
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
//rename
|
||||
client.application.commands.create({
|
||||
name:"rename",
|
||||
description:"Rename this ticket.",
|
||||
defaultPermission:true,
|
||||
type:"CHAT_INPUT",
|
||||
options:[
|
||||
{
|
||||
type:"STRING",
|
||||
name:"name",
|
||||
description:"The new name (without prefix).",
|
||||
required:true
|
||||
}
|
||||
]
|
||||
},sid).then(() => {
|
||||
readystats++
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
const storage = bot.storage
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {discord.Interaction} interaction
|
||||
* @param {String} prefix
|
||||
* @param {"delete"|"close"|"deletenotranscript"} mode
|
||||
*/
|
||||
exports.closeTicket = async (interaction,prefix,mode) => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
const channelmessages = await interaction.channel.messages.fetch()
|
||||
|
||||
channelmessages.sweep((msgSweep) => {
|
||||
return msgSweep.author.id == client.user.id
|
||||
})
|
||||
|
||||
/**
|
||||
* @type {String} ticketuserarray
|
||||
*/
|
||||
const ticketuserarray = interaction.channel.name
|
||||
const ticketusername = ticketuserarray.split(prefix)[1]
|
||||
|
||||
var getuserID = storage.get("userTicketStorage",interaction.channel.id)
|
||||
try {
|
||||
var getusernameStep1 = client.users.cache.find(u => u.id === getuserID)
|
||||
var isDatabaseError = false
|
||||
}catch{
|
||||
var isDatabaseError = true
|
||||
}
|
||||
|
||||
if (!getusernameStep1){
|
||||
console.log(chalk.red("[database error]"),"something went wrong when getting the data in the database.\nNo panic, this error fixes itself!")
|
||||
var isDatabaseError = true
|
||||
}
|
||||
|
||||
var enableTranscript = true
|
||||
|
||||
if (mode == "delete"){
|
||||
interaction.channel.delete()
|
||||
if (config.logs){console.log("[system] deleted a ticket (name:"+interaction.channel.name+",user:"+interaction.user.username+")")}
|
||||
|
||||
if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1)
|
||||
}else if (mode == "close"){
|
||||
var permissionArray = []
|
||||
if (!isDatabaseError) permissionArray.push({
|
||||
id:getusernameStep1.id,
|
||||
type:"member",
|
||||
allow:["VIEW_CHANNEL"],
|
||||
deny:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES"]
|
||||
})
|
||||
|
||||
permissionArray.push({
|
||||
id:interaction.guild.id,
|
||||
type:"role",
|
||||
deny:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
})
|
||||
|
||||
interaction.channel.permissionOverwrites.set(permissionArray)
|
||||
|
||||
//message
|
||||
var closeButtonRow = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicket1")
|
||||
.setDisabled(false)
|
||||
.setStyle("DANGER")
|
||||
.setLabel("Delete Ticket")
|
||||
.setEmoji("✖️")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("sendTranscript")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setLabel("Send Transcript File")
|
||||
.setEmoji("📄")
|
||||
)
|
||||
const embed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setTitle("Closed this ticket!")
|
||||
.setDescription("Only admins can now talk in this ticket!\n\n*Click on the button below to delete this ticket*")
|
||||
interaction.channel.send({embeds:[embed],components:[closeButtonRow]})
|
||||
}else if (mode == "deletenotranscript"){
|
||||
enableTranscript = false
|
||||
interaction.channel.delete()
|
||||
if (config.logs){console.log("[system] deleted a ticket (name:"+interaction.channel.name+",user:"+interaction.user.username+")")}
|
||||
|
||||
if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1)
|
||||
}
|
||||
|
||||
if (enableTranscript == true && mode != "deletenotranscript"){
|
||||
|
||||
if (config.system.enable_transcript || config.system.enable_DM_transcript){
|
||||
var fileattachment = await require("./transcript").createTranscript(channelmessages)
|
||||
|
||||
if (fileattachment == false){console.log("[transcript] internal error: no transcript is created!");return}
|
||||
}
|
||||
|
||||
if (config.system.enable_transcript){
|
||||
const transcriptEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setTitle("A new transcript is here!")
|
||||
.setAuthor({name:interaction.user.username,iconURL:interaction.user.displayAvatarURL({format:"png"})})
|
||||
.setDescription("You can find the transcript in the text file above!")
|
||||
.setFooter({text:"ticket: "+ticketuserarray})
|
||||
|
||||
interaction.guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({
|
||||
embeds:[transcriptEmbed],
|
||||
files:[fileattachment]
|
||||
})
|
||||
}
|
||||
|
||||
if (config.system.enable_DM_transcript){
|
||||
const transcriptEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setTitle("Here is a transcript of your ticket!")
|
||||
.setDescription("You can find the transcript in the text file above!")
|
||||
.setFooter({text:"ticket: "+ticketuserarray})
|
||||
|
||||
if (!isDatabaseError) getusernameStep1.send({
|
||||
embeds:[transcriptEmbed],
|
||||
files:[fileattachment]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.runThis = () => {
|
||||
client.on("interactionCreate",async (interaction) => {
|
||||
if (!interaction.isButton()) return
|
||||
if (interaction.customId != "sendTranscript") return
|
||||
|
||||
interaction.deferUpdate()
|
||||
|
||||
const channelmessages = await interaction.channel.messages.fetch()
|
||||
|
||||
channelmessages.sweep((msgSweep) => {
|
||||
return msgSweep.author.id == client.user.id
|
||||
})
|
||||
|
||||
var fileattachment = await require("./transcript").createTranscript(channelmessages)
|
||||
|
||||
if (fileattachment == false){
|
||||
console.log("[transcript] internal error: no transcript is created!")
|
||||
interaction.channel.send({content:"**Something went wrong while making the transcript!**\nPlease try again another time!"})
|
||||
return
|
||||
}
|
||||
|
||||
interaction.channel.send({content:"**Here is the transcript:**",files:[fileattachment]})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
const getButton = require("./utils/getButton")
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} id the id from an open-ticket embed
|
||||
* @returns {{embed:discord.MessageEmbed,componentRows:discord.MessageActionRow[]}} discord embed
|
||||
*/
|
||||
|
||||
|
||||
|
||||
exports.createEmbed = (id) => {
|
||||
//-----------------------------------
|
||||
//general importing
|
||||
const data = require("./utils/getTicketMessages").getTicketMessage(id)
|
||||
/**@type {discord.MessageButton[]}*/
|
||||
var buttons = []
|
||||
/**@type {getButton.rawButtonData[]} */
|
||||
var buttonData = []
|
||||
|
||||
data.options.forEach((option) => {
|
||||
var button = getButton.getButton(option)
|
||||
var localButtonData = getButton.getOption(option)
|
||||
if (button) buttons.push(button)
|
||||
if (localButtonData) buttonData.push(localButtonData)
|
||||
})
|
||||
//-----------------------------------
|
||||
|
||||
//-----------------------------------
|
||||
//create the embed
|
||||
const embed = new discord.MessageEmbed()
|
||||
.setColor(data.color)
|
||||
.setTitle(data.name)
|
||||
if (data.enableFooter) embed.setFooter({text:data.footer})
|
||||
if (data.enableThumbnail) embed.setThumbnail(data.thumbnail)
|
||||
|
||||
var description = data.description
|
||||
if (data.enableTicketExplaination){
|
||||
description = description+"\n\n__choose a category:__\n"
|
||||
|
||||
var ticketExplainations = []
|
||||
buttonData.forEach((button) => {
|
||||
var explaination = button.icon+" **"+button.name+":**\n"+button.description
|
||||
ticketExplainations.push(explaination)
|
||||
})
|
||||
|
||||
description = description+ticketExplainations.join("\n\n")
|
||||
}
|
||||
|
||||
if (data.enableMaxTicketsWarning){
|
||||
description = description+"\n\n**Warning:** _You can only create "+config.system.max_allowed_tickets+" ticket(s) at a time!_"
|
||||
}
|
||||
|
||||
embed.setDescription(description)
|
||||
//-----------------------------------
|
||||
|
||||
//-----------------------------------
|
||||
//create the components
|
||||
var AmountOfRows = Math.ceil(buttons.length / 4)
|
||||
var currentRow = 0
|
||||
|
||||
/**
|
||||
* @type {discord.MessageActionRow[]}
|
||||
*/
|
||||
var componentRows = []
|
||||
|
||||
for (let i = AmountOfRows; i > 0; i--){
|
||||
|
||||
componentRows.push(new discord.MessageActionRow())
|
||||
}
|
||||
|
||||
buttons.forEach((button,index) => {
|
||||
componentRows[currentRow].addComponents([button])
|
||||
|
||||
if (index == 3 || index == 7 || index == 11 || index == 15 || index == 19 || index == 23 || index == 27 || index == 31 || index == 35 || index == 39){
|
||||
currentRow = currentRow + 1
|
||||
}
|
||||
})
|
||||
//-----------------------------------
|
||||
|
||||
|
||||
|
||||
//return everything
|
||||
/**
|
||||
* @type {{embed:discord.MessageEmbed,componentRows:discord.MessageActionRow[]}}
|
||||
*/
|
||||
const returnedData = {embed:embed,componentRows:componentRows}
|
||||
return returnedData
|
||||
}
|
||||
|
||||
|
||||
this.createEmbed()
|
||||
@@ -0,0 +1,168 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
const getconfigoptions = require("./getoptions")
|
||||
const storage = bot.storage
|
||||
|
||||
module.exports = () => {
|
||||
var closeButton = new discord.MessageActionRow()
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("closeTicket")
|
||||
.setDisabled(false)
|
||||
.setStyle("SECONDARY")
|
||||
.setLabel("Close Ticket")
|
||||
.setEmoji("🔒")
|
||||
)
|
||||
.addComponents(
|
||||
new discord.MessageButton()
|
||||
.setCustomId("deleteTicket")
|
||||
.setDisabled(false)
|
||||
.setStyle("DANGER")
|
||||
.setLabel("Delete Ticket")
|
||||
.setEmoji("✖️")
|
||||
)
|
||||
|
||||
//ticket button click / create ticket
|
||||
client.on("interactionCreate",(interaction) => {
|
||||
if (interaction.isCommand() && (interaction.commandName == "new" || interaction.commandName == "ticket")){
|
||||
var customId = "newT"+interaction.options.getString("type")
|
||||
}else if (interaction.isButton()){
|
||||
var customId = interaction.customId
|
||||
}else return
|
||||
|
||||
if (getconfigoptions.getTicketValues("id").includes(customId)){
|
||||
|
||||
if (interaction.isButton()){
|
||||
interaction.deferUpdate()
|
||||
}else if (interaction.isCommand()){
|
||||
interaction.reply({content:"Your ticket is created!"})
|
||||
}
|
||||
|
||||
//ticketoptions from config
|
||||
const currentTicketOptions = getconfigoptions.getOptionsById(customId)
|
||||
|
||||
if (storage.get("ticketStorage",interaction.member.id) == null || storage.get("ticketStorage",interaction.member.id) == "false"|| Number(storage.get("ticketStorage",interaction.member.id)) < config.system.max_allowed_tickets){
|
||||
|
||||
try{
|
||||
if (config.system.enable_DM_Messages){
|
||||
interaction.member.send({content:currentTicketOptions.message})
|
||||
}
|
||||
}
|
||||
catch{console.log("[system] can't send DM to member, member doesn't allow dm's")}
|
||||
|
||||
|
||||
|
||||
//update storage
|
||||
storage.set("ticketStorage",interaction.member.id,Number(storage.get("ticketStorage",interaction.member.id))+1)
|
||||
var ticketNumber = interaction.member.user.username
|
||||
|
||||
//set ticketName
|
||||
var ticketName = currentTicketOptions.channelprefix+ticketNumber
|
||||
var logsname = currentTicketOptions.name
|
||||
|
||||
//category
|
||||
if (currentTicketOptions.category.length < 16 || currentTicketOptions.category.length > 20){
|
||||
var newTicketCategory = null
|
||||
}else{
|
||||
var newTicketCategory = currentTicketOptions.category
|
||||
}
|
||||
|
||||
var permissionsArray = []
|
||||
|
||||
//set everyone allowed
|
||||
if (config.system['has@everyoneaccess']){
|
||||
var everyoneAllowPerms = ["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
var everyoneDenyPerms = []
|
||||
}else{
|
||||
var everyoneAllowPerms = []
|
||||
var everyoneDenyPerms = ["VIEW_CHANNEL"]
|
||||
}
|
||||
permissionsArray.push({
|
||||
id:interaction.guild.id,
|
||||
type:"role",
|
||||
allow:everyoneAllowPerms,
|
||||
deny:everyoneDenyPerms
|
||||
})
|
||||
|
||||
//add the user that created the ticket
|
||||
permissionsArray.push({
|
||||
id:interaction.member.id,
|
||||
type:"member",
|
||||
allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
})
|
||||
|
||||
//add main adminroles
|
||||
config.main_adminroles.forEach((role) => {
|
||||
permissionsArray.push({
|
||||
id:role,
|
||||
type:"role",
|
||||
allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
})
|
||||
})
|
||||
|
||||
//add ticket adminroles
|
||||
/**
|
||||
* @type {String[]}
|
||||
*/
|
||||
const ticketadmin = currentTicketOptions.adminroles
|
||||
ticketadmin.forEach((role) => {
|
||||
if (!config.main_adminroles.includes(role)){
|
||||
permissionsArray.push({
|
||||
id:role,
|
||||
type:"role",
|
||||
allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
//add member role
|
||||
if (config.system.member_role != "" && config.system.member_role != " " && config.system.member_role != "false" && config.system.member_role != "null" && config.system.member_role != "0"){
|
||||
permissionsArray.push({
|
||||
id:config.system.member_role,
|
||||
type:"role",
|
||||
deny:["VIEW_CHANNEL"]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//create the channel
|
||||
interaction.guild.channels.create(ticketName,{
|
||||
type:"GUILD_TEXT",
|
||||
parent:newTicketCategory,
|
||||
reason:"A new ticket was created",
|
||||
permissionOverwrites:permissionsArray
|
||||
|
||||
}).then((ticketChannel) => {
|
||||
storage.set("userTicketStorage",ticketChannel.id,interaction.member.id)
|
||||
|
||||
var ticketEmbed = new discord.MessageEmbed()
|
||||
.setColor(config.main_color)
|
||||
.setTitle("You created a ticket!")
|
||||
.setDescription("The staff will help you soon!\n\n*Click on the button below to close the ticket!*")
|
||||
|
||||
ticketChannel.send({
|
||||
content:"<@"+interaction.member.id+"> @everyone",
|
||||
embeds:[ticketEmbed],
|
||||
components:[closeButton]
|
||||
|
||||
}).then(firstmsg => {
|
||||
firstmsg.pin()
|
||||
})
|
||||
if (config.logs){console.log("[system] created a new ticket (name:"+logsname+",user:"+interaction.user.username+")")}
|
||||
})
|
||||
}else{
|
||||
try {
|
||||
if (config.system.enable_DM_Messages){
|
||||
interaction.member.send("you already have the maximum number of tickets allowed!")
|
||||
}
|
||||
}
|
||||
catch{console.log("[system] can't send DM to member, member doesn't allow dm's")}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
const discord = require('discord.js')
|
||||
const bot = require('../index')
|
||||
const client = bot.client
|
||||
const config = bot.config
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {discord.Message[]} messagecollection
|
||||
* @returns new `discord.messageAttachment`
|
||||
*/
|
||||
|
||||
exports.createTranscript = async (messagecollection) => {
|
||||
try {
|
||||
const filearray = ["TRANSCRIPT START:"]
|
||||
|
||||
messagecollection.reverse()
|
||||
|
||||
|
||||
messagecollection.forEach((msg) => {
|
||||
const timestamp = new Date(msg.createdTimestamp)
|
||||
|
||||
if (msg.content){var content = msg.content}else{var content = "*empty message*"}
|
||||
|
||||
const msgstats = "files: "+msg.attachments.size+" | embeds: "+msg.embeds.length+" | isbot: "+msg.author.bot
|
||||
filearray.push("["+timestamp.getDate()+"/"+timestamp.getMonth()+"/"+timestamp.getFullYear()+" | "+timestamp.getHours()+":"+timestamp.getMinutes()+":"+timestamp.getSeconds()+" | "+msg.author.tag+" ] ["+msgstats+"]\n"+content+"\n")
|
||||
})
|
||||
|
||||
if (filearray.length < 2) filearray.push("transcript is empty")
|
||||
const filestring = filearray.join("\n")
|
||||
const filebuff = Buffer.from(filestring,"utf-8")
|
||||
return new discord.MessageAttachment(filebuff,"transcript.txt")
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
const discord = require("discord.js")
|
||||
const bot = require("../../index")
|
||||
const config = bot.config
|
||||
const getoptions = require("../getoptions")
|
||||
|
||||
/**@returns {"DANGER"|"SUCCESS"|"PRIMARY"|"SECONDARY"} */
|
||||
const getColor = (color) => {
|
||||
if (color.toLowerCase() == "red"){
|
||||
return "DANGER"
|
||||
}else if (color.toLowerCase() == "green"){
|
||||
return "SUCCESS"
|
||||
}else if (color.toLowerCase() == "blue" || color.toLowerCase() == "blurple"){
|
||||
return "PRIMARY"
|
||||
}else if (color.toLowerCase() == "black" || color.toLowerCase() == "gray" || color.toLowerCase() == "grey"){
|
||||
return "SECONDARY"
|
||||
}else if (color == "DANGER" || color == "SECONDARY" || color == "SUCCESS" || color == "PRIMARY"){
|
||||
return color
|
||||
}else if (color.toLowerCase() == "none" || color.toLowerCase() == "false" || color.toLowerCase() == ""){
|
||||
return "SECONDARY"
|
||||
}else return "SECONDARY"
|
||||
}
|
||||
|
||||
const getOption = (id) => {
|
||||
const result = config.options.find((option) => option.id == id)
|
||||
if (!result){return false}else return result
|
||||
}
|
||||
exports.getOption = getOption
|
||||
/**
|
||||
*
|
||||
* @param {String} id
|
||||
* @returns {discord.MessageButton|false}
|
||||
*/
|
||||
exports.getButton = (id) => {
|
||||
const option = getOption(id)
|
||||
if (!option) return false
|
||||
if (option.type == "ticket"){
|
||||
var button = new discord.MessageButton()
|
||||
.setCustomId("newT"+option.id)
|
||||
.setDisabled(false)
|
||||
.setStyle(getColor(option.color))
|
||||
|
||||
if (option.label){button.setLabel(option.label)}
|
||||
if (option.icon){button.setEmoji(option.icon)}
|
||||
if (!option.label && !option.icon){button.setLabel("no label or emoji")}
|
||||
|
||||
}else if (option.type == "website"){
|
||||
var button = new discord.MessageButton()
|
||||
.setDisabled(false)
|
||||
.setStyle("LINK")
|
||||
.setURL(option.url)
|
||||
|
||||
if (option.label){button.setLabel(option.label)}
|
||||
if (option.icon){button.setEmoji(option.icon)}
|
||||
if (!option.label && !option.icon){button.setLabel("no label or emoji")}
|
||||
|
||||
}else if (option.type == "role"){
|
||||
var button = new discord.MessageButton()
|
||||
.setCustomId("newR"+option.id)
|
||||
.setDisabled(false)
|
||||
.setStyle(getColor(option.color))
|
||||
|
||||
if (option.label){button.setLabel(option.label)}
|
||||
if (option.icon){button.setEmoji(option.icon)}
|
||||
if (!option.label && !option.icon){button.setLabel("no label or emoji")}
|
||||
|
||||
}
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
|
||||
exports.rawButtonData = class {
|
||||
constructor() {
|
||||
this.id = ""
|
||||
this.name = ""
|
||||
this.description = ""
|
||||
this.icon = ""
|
||||
this.label = ""
|
||||
this.type = ""
|
||||
|
||||
this.color = ""
|
||||
this.enableDMMessage = true
|
||||
this.url = ""
|
||||
this.roles = ["",""]
|
||||
this.mode = ""
|
||||
this.adminroles = ["",""]
|
||||
this.channelprefix = ""
|
||||
this.category = ""
|
||||
this.message = ""
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
const bot = require("../../index")
|
||||
const config = bot.config
|
||||
exports.getTicketMessage = (input) => {
|
||||
var returned = config.messages.find(a => a.id == input)
|
||||
if (returned){
|
||||
return returned
|
||||
}
|
||||
var result = config.messages[0]
|
||||
if (!result){
|
||||
throw new Error("'messages' object in config.json is empty")
|
||||
return
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,28 +1,125 @@
|
||||
const discord = require('discord.js')
|
||||
const config = require('./config.json')
|
||||
const fs = require('fs')
|
||||
const intents = discord.Intents
|
||||
const client = new discord.Client({intents:[intents.FLAGS.GUILDS,intents.FLAGS.GUILD_MESSAGES,intents.FLAGS.GUILD_MEMBERS]})
|
||||
const client = new discord.Client({intents:[intents.FLAGS.GUILDS,intents.FLAGS.GUILD_MESSAGES,intents.FLAGS.GUILD_MEMBERS],partials:["CHANNEL"]})
|
||||
exports.client = client
|
||||
|
||||
client.on('ready',() => {
|
||||
console.log('ready')
|
||||
client.setMaxListeners(20)
|
||||
|
||||
//change to FALSE on release
|
||||
const isDev = false
|
||||
//!!!!!!!!!!!
|
||||
|
||||
if (isDev){
|
||||
try {
|
||||
var config = require('./devConfig.json')
|
||||
}catch{
|
||||
console.log("devConfig.json not found! Trying the normal config...")
|
||||
var config = require("./config.json")
|
||||
}
|
||||
}else{var config = require('./config.json')}
|
||||
exports.config = config
|
||||
|
||||
client.on('ready',async () => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
if (process.argv[2] != "slash"){
|
||||
console.log(chalk.green("open-ticket ready!"))
|
||||
if (config.logs){console.log(chalk.white("\n\nlogs:\n============"))}
|
||||
if (config.status.enabled){
|
||||
client.user.setActivity(config.status.text,{type:config.status.type})
|
||||
}
|
||||
}else{
|
||||
console.log(chalk.red("STARTING IN ")+chalk.blue("SLASH MODE")+chalk.red("..."))
|
||||
console.log("logs:\n================")
|
||||
console.log("client logged in...")
|
||||
console.log("loading files...")
|
||||
if (process.argv[3] == "enable"){
|
||||
console.log(chalk.green("switching to slashEnable.js"))
|
||||
require("./core/slashSystem/slashEnable")()
|
||||
}else if (process.argv[3] == "disable"){
|
||||
console.log(chalk.green("switching to slashDisable.js"))
|
||||
require("./core/slashSystem/slashDisable")()
|
||||
}else{
|
||||
console.log(chalk.red("Internal Error: unknown slash mode!"))
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var storage = require('./storage/storage')
|
||||
exports.TicketStorage = storage.ticketStorage
|
||||
exports.userTicketStorage = storage.userTicketStorage
|
||||
exports.transcriptStorage = storage.transcriptStorage
|
||||
exports.ticketNumberStorage = storage.ticketNumberStorage
|
||||
require("./core/checker").checker()
|
||||
|
||||
var ticket = require('./commands/ticket')
|
||||
ticket()
|
||||
if (process.argv[2] != "slash"){
|
||||
var storage = require('./core/dynamicdatabase/storage')
|
||||
exports.storage = storage
|
||||
|
||||
var ticketSystem = require('./commands/ticketSystem')
|
||||
ticketSystem()
|
||||
//commands
|
||||
require('./commands/ticket')()
|
||||
require("./commands/help")()
|
||||
require("./commands/close")()
|
||||
require("./commands/delete")()
|
||||
require("./commands/rename")()
|
||||
require("./commands/add")()
|
||||
require("./commands/remove")()
|
||||
|
||||
var ticketExtra = require("./commands/ticketExtra")
|
||||
ticketExtra()
|
||||
//core
|
||||
require('./core/ticketOpener')()
|
||||
require("./core/ticketCloser").runThis()
|
||||
require("./core/closebuttons")()
|
||||
require("./core/reactionRoles")()
|
||||
|
||||
/**
|
||||
* We need:
|
||||
* - checker.js
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//=====================================================================
|
||||
//ERROR DEBUG MODE: turn not on exept when you know what you are doing!
|
||||
var errorDebugMode = false
|
||||
//ERROR DEBUG MODE: turn not on exept when you know what you are doing!
|
||||
//=====================================================================
|
||||
//=====================================================================
|
||||
|
||||
|
||||
|
||||
if (!errorDebugMode){
|
||||
process.on("uncaughtException",async (error,origin) => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
console.log(chalk.red("\nOPEN TICKET ERROR: ")+error+"\n"+chalk.green("\nCreate a ticket in our support server for more information!\nIf you do this, you might help us to avoid a future bug!\n"))
|
||||
})
|
||||
}
|
||||
if (errorDebugMode) {
|
||||
const debugLog = (debugString) => {
|
||||
const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n<OPEN TICKET DEBUG FILE:>\n=========================="
|
||||
fs.writeFileSync("./openticketdebug.txt",content+"\nDEBUG: "+debugString)
|
||||
}
|
||||
const errorLog = (errorString,stack) => {
|
||||
const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n<OPEN TICKET DEBUG FILE:>\n=========================="
|
||||
fs.writeFileSync("./openticketdebug.txt",content+"\nERROR: "+errorString+" STACK: "+stack)
|
||||
}
|
||||
|
||||
client.on("debug", async (message) => {
|
||||
if (message.startsWith("Provided token:")){
|
||||
debugLog("Provided token: ***********bot token is invisible**************...")
|
||||
return
|
||||
}
|
||||
debugLog(message)
|
||||
});
|
||||
|
||||
const asyncfunction = async () => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
console.log("\n\nopen-ticket debug:\n"+chalk.bgYellow("ENTERING DEBUG MODE:"))
|
||||
}
|
||||
asyncfunction()
|
||||
|
||||
process.on("uncaughtException",async (error,origin) => {
|
||||
const chalk = await (await import("chalk")).default
|
||||
console.log(chalk.red("\nMAIN ERROR: ")+"this error is saved in the debug file!")
|
||||
errorLog(error.name+": "+error.message+" | origin: "+origin,error.stack)
|
||||
})
|
||||
}
|
||||
|
||||
client.login(config.auth_token)
|
||||
+19
-8
@@ -1,19 +1,30 @@
|
||||
{
|
||||
"name": "safemt-tickets",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"name": "open-ticket",
|
||||
"version": "2.0.0",
|
||||
"description": "This is an open-source discord ticket bot, you can configure it and it comes with cool features like a transcript.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"slashEnable": "node index.js slash enable",
|
||||
"slashDisable": "node index.js slash disable",
|
||||
"cleardata": "node ./core/dynamicdatabase/cleardata.js"
|
||||
},
|
||||
"author": "",
|
||||
"author": "DJdj Development",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"canvas": "^2.8.0",
|
||||
"discord.js": "^13.2.0",
|
||||
"chalk": "^5.0.1",
|
||||
"discord.js": "^13.6.0",
|
||||
"express": "^4.17.1",
|
||||
"node": "^16.10.0",
|
||||
"node-localstorage": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/DJj123dj/open-ticket.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/DJj123dj/open-ticket/issues"
|
||||
},
|
||||
"homepage": "https://github.com/DJj123dj/open-ticket#readme"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user