nv-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -0
- package/package.json +16 -0
- package/src/command-handler/ChannelCommands.js +52 -0
- package/src/command-handler/Command.js +21 -0
- package/src/command-handler/CommandHandler.js +219 -0
- package/src/command-handler/CustomCommands.js +74 -0
- package/src/command-handler/DisabledCommands.js +50 -0
- package/src/command-handler/PrefixHandler.js +50 -0
- package/src/command-handler/SlashCommands.js +111 -0
- package/src/command-handler/commands/channelcommand.js +69 -0
- package/src/command-handler/commands/customcommand.js +28 -0
- package/src/command-handler/commands/delcustomcmd.js +21 -0
- package/src/command-handler/commands/prefix.js +21 -0
- package/src/command-handler/commands/requiredpermissions.js +110 -0
- package/src/command-handler/commands/requiredroles.js +112 -0
- package/src/command-handler/commands/togglecommand.js +42 -0
- package/src/command-handler/validations/run-time/argument-count.js +24 -0
- package/src/command-handler/validations/run-time/channel-command.js +26 -0
- package/src/command-handler/validations/run-time/disabled-commands.js +21 -0
- package/src/command-handler/validations/run-time/guild-only.js +15 -0
- package/src/command-handler/validations/run-time/has-permissions.js +50 -0
- package/src/command-handler/validations/run-time/has-roles.js +43 -0
- package/src/command-handler/validations/run-time/owner-only.js +12 -0
- package/src/command-handler/validations/run-time/test-only.js +10 -0
- package/src/command-handler/validations/runtime/argument-count.js +24 -0
- package/src/command-handler/validations/runtime/channel-command.js +26 -0
- package/src/command-handler/validations/runtime/disabled-commands.js +21 -0
- package/src/command-handler/validations/runtime/guild-only.js +15 -0
- package/src/command-handler/validations/runtime/has-permissions.js +50 -0
- package/src/command-handler/validations/runtime/has-roles.js +43 -0
- package/src/command-handler/validations/runtime/owner-only.js +12 -0
- package/src/command-handler/validations/runtime/test-only.js +10 -0
- package/src/command-handler/validations/syntax/bad-cooldown-types.js +28 -0
- package/src/command-handler/validations/syntax/callback-required.js +9 -0
- package/src/command-handler/validations/syntax/defer-reply.js +14 -0
- package/src/command-handler/validations/syntax/desc-required-for-slash.js +11 -0
- package/src/command-handler/validations/syntax/owner-only-without-owners.js +11 -0
- package/src/command-handler/validations/syntax/permissions-without-guild-only.js +10 -0
- package/src/command-handler/validations/syntax/test-without-server.js +11 -0
- package/src/event-handler/EventHandler.js +87 -0
- package/src/event-handler/events/interactionCreate/isButton/test.js +3 -0
- package/src/event-handler/events/interactionCreate/isCommand/slash-commands.js +77 -0
- package/src/event-handler/events/messageCreate/isHuman/legacy-commands.js +36 -0
- package/src/index.js +90 -0
- package/src/models/channel-commands-schema.js +16 -0
- package/src/models/cooldown-schema.js +16 -0
- package/src/models/custom-command-schema.js +16 -0
- package/src/models/disabled-commands-schema.js +12 -0
- package/src/models/guild-prefix-schema.js +16 -0
- package/src/models/required-permissions-schema.js +16 -0
- package/src/models/required-roles-schema.js +16 -0
- package/src/util/Cooldowns.js +232 -0
- package/src/util/FeatureHandler.js +20 -0
- package/src/util/get-all-files.js +28 -0
package/README.md
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nv-kit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"discord.js": "^14.0.2",
|
|
14
|
+
"mongoose": "^6.3.5"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const channelCommands = require('../models/channel-commands-schema')
|
|
2
|
+
|
|
3
|
+
class ChannelCommands {
|
|
4
|
+
// `${guildId}-${commandName}`: [channelIds]
|
|
5
|
+
_channelCommands = new Map()
|
|
6
|
+
|
|
7
|
+
async action(action, guildId, commandName, channelId) {
|
|
8
|
+
const _id = `${guildId}-${commandName}`
|
|
9
|
+
|
|
10
|
+
const result = await channelCommands.findOneAndUpdate(
|
|
11
|
+
{
|
|
12
|
+
_id,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
_id,
|
|
16
|
+
[action === 'add' ? '$addToSet' : '$pull']: {
|
|
17
|
+
channels: channelId,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
upsert: true,
|
|
22
|
+
new: true,
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
this._channelCommands.set(_id, result.channels)
|
|
27
|
+
return result.channels
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async add(guildId, commandName, channelId) {
|
|
31
|
+
return await this.action('add', guildId, commandName, channelId)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async remove(guildId, commandName, channelId) {
|
|
35
|
+
return await this.action('remove', guildId, commandName, channelId)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getAvailableChannels(guildId, commandName) {
|
|
39
|
+
const _id = `${guildId}-${commandName}`
|
|
40
|
+
let channels = this._channelCommands.get(_id)
|
|
41
|
+
|
|
42
|
+
if (!channels) {
|
|
43
|
+
const results = await channelCommands.findById(_id)
|
|
44
|
+
channels = results ? results.channels : []
|
|
45
|
+
this._channelCommands.set(_id, channels)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return channels
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = ChannelCommands
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Command {
|
|
2
|
+
constructor(instance, commandName, commandObject) {
|
|
3
|
+
this._instance = instance
|
|
4
|
+
this._commandName = commandName.toLowerCase()
|
|
5
|
+
this._commandObject = commandObject
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
get instance() {
|
|
9
|
+
return this._instance
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get commandName() {
|
|
13
|
+
return this._commandName
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get commandObject() {
|
|
17
|
+
return this._commandObject
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = Command
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
3
|
+
const getAllFiles = require('../util/get-all-files')
|
|
4
|
+
const Command = require('./Command')
|
|
5
|
+
const SlashCommands = require('./SlashCommands')
|
|
6
|
+
const { cooldownTypes } = require('../util/Cooldowns')
|
|
7
|
+
const ChannelCommands = require('./ChannelCommands')
|
|
8
|
+
const CustomCommands = require('./CustomCommands')
|
|
9
|
+
const DisabledCommands = require('./DisabledCommands')
|
|
10
|
+
const PrefixHandler = require('./PrefixHandler')
|
|
11
|
+
|
|
12
|
+
class CommandHandler {
|
|
13
|
+
// <commandName, instance of the Command class>
|
|
14
|
+
_commands = new Map()
|
|
15
|
+
_validations = this.getValidations(
|
|
16
|
+
path.join(__dirname, 'validations', 'runtime')
|
|
17
|
+
)
|
|
18
|
+
_channelCommands = new ChannelCommands()
|
|
19
|
+
_customCommands = new CustomCommands(this)
|
|
20
|
+
_disabledCommands = new DisabledCommands()
|
|
21
|
+
_prefixes = new PrefixHandler()
|
|
22
|
+
|
|
23
|
+
constructor(instance, commandsDir, client) {
|
|
24
|
+
this._instance = instance
|
|
25
|
+
this._commandsDir = commandsDir
|
|
26
|
+
this._slashCommands = new SlashCommands(client)
|
|
27
|
+
this._client = client
|
|
28
|
+
|
|
29
|
+
this._validations = [
|
|
30
|
+
...this._validations,
|
|
31
|
+
...this.getValidations(instance.validations?.runtime),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
this.readFiles()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get commands() {
|
|
38
|
+
return this._commands
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get channelCommands() {
|
|
42
|
+
return this._channelCommands
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get slashCommands() {
|
|
46
|
+
return this._slashCommands
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get customCommands() {
|
|
50
|
+
return this._customCommands
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get disabledCommands() {
|
|
54
|
+
return this._disabledCommands
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get prefixHandler() {
|
|
58
|
+
return this._prefixes
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async readFiles() {
|
|
62
|
+
const defaultCommands = getAllFiles(path.join(__dirname, './commands'))
|
|
63
|
+
const files = getAllFiles(this._commandsDir)
|
|
64
|
+
const validations = [
|
|
65
|
+
...this.getValidations(path.join(__dirname, 'validations', 'syntax')),
|
|
66
|
+
...this.getValidations(this._instance.validations?.syntax),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
for (let file of [...defaultCommands, ...files]) {
|
|
70
|
+
const commandObject = require(file)
|
|
71
|
+
|
|
72
|
+
let commandName = file.split(/[\/\\]/)
|
|
73
|
+
commandName = commandName.pop()
|
|
74
|
+
commandName = commandName.split('.')[0]
|
|
75
|
+
|
|
76
|
+
const command = new Command(this._instance, commandName, commandObject)
|
|
77
|
+
|
|
78
|
+
const {
|
|
79
|
+
description,
|
|
80
|
+
type,
|
|
81
|
+
testOnly,
|
|
82
|
+
delete: del,
|
|
83
|
+
aliases = [],
|
|
84
|
+
init = () => {},
|
|
85
|
+
} = commandObject
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
del ||
|
|
89
|
+
this._instance.disabledDefaultCommands.includes(
|
|
90
|
+
commandName.toLowerCase()
|
|
91
|
+
)
|
|
92
|
+
) {
|
|
93
|
+
if (type === 'SLASH' || type === 'BOTH') {
|
|
94
|
+
if (testOnly) {
|
|
95
|
+
for (const guildId of this._instance.testServers) {
|
|
96
|
+
this._slashCommands.delete(command.commandName, guildId)
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
this._slashCommands.delete(command.commandName)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (const validation of validations) {
|
|
107
|
+
validation(command)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await init(this._client, this._instance)
|
|
111
|
+
|
|
112
|
+
const names = [command.commandName, ...aliases]
|
|
113
|
+
|
|
114
|
+
for (const name of names) {
|
|
115
|
+
this._commands.set(name, command)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (type === 'SLASH' || type === 'BOTH') {
|
|
119
|
+
const options =
|
|
120
|
+
commandObject.options ||
|
|
121
|
+
this._slashCommands.createOptions(commandObject)
|
|
122
|
+
|
|
123
|
+
if (testOnly) {
|
|
124
|
+
for (const guildId of this._instance.testServers) {
|
|
125
|
+
this._slashCommands.create(
|
|
126
|
+
command.commandName,
|
|
127
|
+
description,
|
|
128
|
+
options,
|
|
129
|
+
guildId
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
this._slashCommands.create(command.commandName, description, options)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async runCommand(command, args, message, interaction) {
|
|
140
|
+
const { callback, type, cooldowns } = command.commandObject
|
|
141
|
+
|
|
142
|
+
if (message && type === 'SLASH') {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const guild = message ? message.guild : interaction.guild
|
|
147
|
+
const member = message ? message.member : interaction.member
|
|
148
|
+
const user = message ? message.author : interaction.user
|
|
149
|
+
const channel = message ? message.channel : interaction.channel
|
|
150
|
+
|
|
151
|
+
const usage = {
|
|
152
|
+
instance: command.instance,
|
|
153
|
+
message,
|
|
154
|
+
interaction,
|
|
155
|
+
args,
|
|
156
|
+
text: args.join(' '),
|
|
157
|
+
guild,
|
|
158
|
+
member,
|
|
159
|
+
user,
|
|
160
|
+
channel,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
for (const validation of this._validations) {
|
|
164
|
+
if (!(await validation(command, usage, this._prefixes.get(guild?.id)))) {
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (cooldowns) {
|
|
170
|
+
let cooldownType
|
|
171
|
+
|
|
172
|
+
for (const type of cooldownTypes) {
|
|
173
|
+
if (cooldowns[type]) {
|
|
174
|
+
cooldownType = type
|
|
175
|
+
break
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const cooldownUsage = {
|
|
180
|
+
cooldownType,
|
|
181
|
+
userId: user.id,
|
|
182
|
+
actionId: `command_${command.commandName}`,
|
|
183
|
+
guildId: guild?.id,
|
|
184
|
+
duration: cooldowns[cooldownType],
|
|
185
|
+
errorMessage: cooldowns.errorMessage,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const result = this._instance.cooldowns.canRunAction(cooldownUsage)
|
|
189
|
+
|
|
190
|
+
if (typeof result === 'string') {
|
|
191
|
+
return result
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
await this._instance.cooldowns.start(cooldownUsage)
|
|
195
|
+
|
|
196
|
+
usage.cancelCooldown = () => {
|
|
197
|
+
this._instance.cooldowns.cancelCooldown(cooldownUsage)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
usage.updateCooldown = (expires) => {
|
|
201
|
+
this._instance.cooldowns.updateCooldown(cooldownUsage, expires)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return await callback(usage)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
getValidations(folder) {
|
|
209
|
+
if (!folder) {
|
|
210
|
+
return []
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const validations = getAllFiles(folder).map((filePath) => require(filePath))
|
|
214
|
+
|
|
215
|
+
return validations
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = CommandHandler
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const customCommandSchema = require('../models/custom-command-schema')
|
|
2
|
+
|
|
3
|
+
class CustomCommands {
|
|
4
|
+
// guildId-commandName: response
|
|
5
|
+
_customCommands = new Map()
|
|
6
|
+
|
|
7
|
+
constructor(commandHandler) {
|
|
8
|
+
this._commandHandler = commandHandler
|
|
9
|
+
this.loadCommands()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async loadCommands() {
|
|
13
|
+
const results = await customCommandSchema.find({})
|
|
14
|
+
|
|
15
|
+
for (const result of results) {
|
|
16
|
+
const { _id, response } = result
|
|
17
|
+
this._customCommands.set(_id, response)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async create(guildId, commandName, description, response) {
|
|
22
|
+
const _id = `${guildId}-${commandName}`
|
|
23
|
+
|
|
24
|
+
this._customCommands.set(_id, response)
|
|
25
|
+
|
|
26
|
+
this._commandHandler.slashCommands.create(
|
|
27
|
+
commandName,
|
|
28
|
+
description,
|
|
29
|
+
[],
|
|
30
|
+
guildId
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
await customCommandSchema.findOneAndUpdate(
|
|
34
|
+
{
|
|
35
|
+
_id,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
_id,
|
|
39
|
+
response,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
upsert: true,
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async delete(guildId, commandName) {
|
|
48
|
+
const _id = `${guildId}-${commandName}`
|
|
49
|
+
|
|
50
|
+
this._customCommands.delete(_id)
|
|
51
|
+
|
|
52
|
+
this._commandHandler.slashCommands.delete(commandName, guildId)
|
|
53
|
+
|
|
54
|
+
await customCommandSchema.deleteOne({ _id })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async run(commandName, message, interaction) {
|
|
58
|
+
const guild = message ? message.guild : interaction.guild
|
|
59
|
+
if (!guild) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const _id = `${guild.id}-${commandName}`
|
|
64
|
+
const response = this._customCommands.get(_id)
|
|
65
|
+
if (!response) {
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (message) message.channel.send(response).catch(() => {})
|
|
70
|
+
else if (interaction) interaction.reply(response).catch(() => {})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = CustomCommands
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const disabledCommandSchema = require('../models/disabled-commands-schema')
|
|
2
|
+
|
|
3
|
+
class DisabledCommands {
|
|
4
|
+
// array of `${guildId}-${commandName}`
|
|
5
|
+
_disabledCommands = []
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
this.loadDisabledCommands()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async loadDisabledCommands() {
|
|
12
|
+
const results = await disabledCommandSchema.find({})
|
|
13
|
+
|
|
14
|
+
for (const result of results) {
|
|
15
|
+
this._disabledCommands.push(result._id)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async disable(guildId, commandName) {
|
|
20
|
+
if (this.isDisabled(guildId, commandName)) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const _id = `${guildId}-${commandName}`
|
|
25
|
+
this._disabledCommands.push(_id)
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
await new disabledCommandSchema({
|
|
29
|
+
_id,
|
|
30
|
+
}).save()
|
|
31
|
+
} catch (ignored) {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async enable(guildId, commandName) {
|
|
35
|
+
if (!this.isDisabled(guildId, commandName)) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const _id = `${guildId}-${commandName}`
|
|
40
|
+
this._disabledCommands = this._disabledCommands.filter((id) => id !== _id)
|
|
41
|
+
|
|
42
|
+
await disabledCommandSchema.deleteOne({ _id })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
isDisabled(guildId, commandName) {
|
|
46
|
+
return this._disabledCommands.includes(`${guildId}-${commandName}`)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = DisabledCommands
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const guildPrefixSchema = require('../models/guild-prefix-schema')
|
|
2
|
+
|
|
3
|
+
class PrefixHandler {
|
|
4
|
+
// <guildId: prefix>
|
|
5
|
+
_prefixes = new Map()
|
|
6
|
+
_defaultPrefix = '!'
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
this.loadPrefixes()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async loadPrefixes() {
|
|
13
|
+
const results = await guildPrefixSchema.find({})
|
|
14
|
+
|
|
15
|
+
for (const result of results) {
|
|
16
|
+
this._prefixes.set(result._id, result.prefix)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get defaultPrefix() {
|
|
21
|
+
return this._defaultPrefix
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get(guildId) {
|
|
25
|
+
if (!guildId) {
|
|
26
|
+
return defaultPrefix
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return this._prefixes.get(guildId) || this.defaultPrefix
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async set(guildId, prefix) {
|
|
33
|
+
this._prefixes.set(guildId, prefix)
|
|
34
|
+
|
|
35
|
+
await guildPrefixSchema.findOneAndUpdate(
|
|
36
|
+
{
|
|
37
|
+
_id: guildId,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
_id: guildId,
|
|
41
|
+
prefix,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
upsert: true,
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = PrefixHandler
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const { ApplicationCommandOptionType } = require('discord.js')
|
|
2
|
+
|
|
3
|
+
class SlashCommands {
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this._client = client
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async getCommands(guildId) {
|
|
9
|
+
let commands
|
|
10
|
+
|
|
11
|
+
if (guildId) {
|
|
12
|
+
const guild = await this._client.guilds.fetch(guildId)
|
|
13
|
+
commands = guild.commands
|
|
14
|
+
} else {
|
|
15
|
+
commands = this._client.application.commands
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await commands.fetch()
|
|
19
|
+
|
|
20
|
+
return commands
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
areOptionsDifferent(options, existingOptions) {
|
|
24
|
+
for (let a = 0; a < options.length; ++a) {
|
|
25
|
+
const option = options[a]
|
|
26
|
+
const existing = existingOptions[a]
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
option.name !== existing.name ||
|
|
30
|
+
option.type !== existing.type ||
|
|
31
|
+
option.description !== existing.description
|
|
32
|
+
) {
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async create(name, description, options, guildId) {
|
|
41
|
+
const commands = await this.getCommands(guildId)
|
|
42
|
+
|
|
43
|
+
const existingCommand = commands.cache.find((cmd) => cmd.name === name)
|
|
44
|
+
if (existingCommand) {
|
|
45
|
+
const { description: existingDescription, options: existingOptions } =
|
|
46
|
+
existingCommand
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
description !== existingDescription ||
|
|
50
|
+
options.length !== existingOptions.length ||
|
|
51
|
+
this.areOptionsDifferent(options, existingOptions)
|
|
52
|
+
) {
|
|
53
|
+
console.log(`Updating the command "${name}"`)
|
|
54
|
+
|
|
55
|
+
await commands.edit(existingCommand.id, {
|
|
56
|
+
description,
|
|
57
|
+
options,
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await commands.create({
|
|
64
|
+
name,
|
|
65
|
+
description,
|
|
66
|
+
options,
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async delete(commandName, guildId) {
|
|
71
|
+
const commands = await this.getCommands(guildId)
|
|
72
|
+
|
|
73
|
+
const existingCommand = commands.cache.find(
|
|
74
|
+
(cmd) => cmd.name === commandName
|
|
75
|
+
)
|
|
76
|
+
if (!existingCommand) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await existingCommand.delete()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
createOptions({ expectedArgs = '', minArgs = 0 }) {
|
|
84
|
+
const options = []
|
|
85
|
+
|
|
86
|
+
// <num 1> <num 2>
|
|
87
|
+
|
|
88
|
+
if (expectedArgs) {
|
|
89
|
+
const split = expectedArgs
|
|
90
|
+
.substring(1, expectedArgs.length - 1)
|
|
91
|
+
// num 1> <num 2
|
|
92
|
+
.split(/[>\]] [<\[]/)
|
|
93
|
+
// ['num 1', 'num 2']
|
|
94
|
+
|
|
95
|
+
for (let a = 0; a < split.length; ++a) {
|
|
96
|
+
const arg = split[a]
|
|
97
|
+
|
|
98
|
+
options.push({
|
|
99
|
+
name: arg.toLowerCase().replace(/\s+/g, '-'),
|
|
100
|
+
description: arg,
|
|
101
|
+
type: ApplicationCommandOptionType.String,
|
|
102
|
+
required: a < minArgs,
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return options
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = SlashCommands
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const { ApplicationCommandOptionType } = require('discord.js')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
description: 'Specifies what commands can be ran inside of what channels',
|
|
5
|
+
|
|
6
|
+
type: 'SLASH',
|
|
7
|
+
testOnly: true,
|
|
8
|
+
guildOnly: true,
|
|
9
|
+
|
|
10
|
+
options: [
|
|
11
|
+
{
|
|
12
|
+
name: 'command',
|
|
13
|
+
description: 'The command to restrict to specific channels',
|
|
14
|
+
required: true,
|
|
15
|
+
type: ApplicationCommandOptionType.String,
|
|
16
|
+
autocomplete: true,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'channel',
|
|
20
|
+
description: 'The channel to use for this command',
|
|
21
|
+
required: true,
|
|
22
|
+
type: ApplicationCommandOptionType.Channel,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
|
|
26
|
+
autocomplete: (_, command) => {
|
|
27
|
+
return [...command.instance.commandHandler.commands.keys()]
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
callback: async ({ instance, guild, interaction }) => {
|
|
31
|
+
const commandName = interaction.options.getString('command')
|
|
32
|
+
const channel = interaction.options.getChannel('channel')
|
|
33
|
+
|
|
34
|
+
const command = instance.commandHandler.commands.get(
|
|
35
|
+
commandName.toLowerCase()
|
|
36
|
+
)
|
|
37
|
+
if (!command) {
|
|
38
|
+
return `The command "${commandName}" does not exist.`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { channelCommands } = instance.commandHandler
|
|
42
|
+
|
|
43
|
+
let availableChannels = []
|
|
44
|
+
const canRun = (
|
|
45
|
+
await channelCommands.getAvailableChannels(guild.id, commandName)
|
|
46
|
+
).includes(channel.id)
|
|
47
|
+
|
|
48
|
+
if (canRun) {
|
|
49
|
+
availableChannels = await channelCommands.remove(
|
|
50
|
+
guild.id,
|
|
51
|
+
commandName,
|
|
52
|
+
channel.id
|
|
53
|
+
)
|
|
54
|
+
} else {
|
|
55
|
+
availableChannels = await channelCommands.add(
|
|
56
|
+
guild.id,
|
|
57
|
+
commandName,
|
|
58
|
+
channel.id
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (availableChannels.length) {
|
|
63
|
+
const channelNames = availableChannels.map((c) => `<#${c}> `)
|
|
64
|
+
return `The command "${commandName}" can now only be ran inside of the following channels: ${channelNames}`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return `The command "${commandName}" can now be ran inside of any text channel.`
|
|
68
|
+
},
|
|
69
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const { PermissionFlagsBits } = require('discord.js')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
description: 'Creates a custom command',
|
|
5
|
+
|
|
6
|
+
minArgs: 3,
|
|
7
|
+
syntaxError: 'Correct syntax: {PREFIX}customCommand {ARGS}',
|
|
8
|
+
expectedArgs: '<command name> <description> <response>',
|
|
9
|
+
|
|
10
|
+
type: 'SLASH',
|
|
11
|
+
guildOnly: true,
|
|
12
|
+
testOnly: true,
|
|
13
|
+
|
|
14
|
+
permissions: [PermissionFlagsBits.Administrator],
|
|
15
|
+
|
|
16
|
+
callback: async ({ instance, args, guild }) => {
|
|
17
|
+
const [commandName, description, response] = args
|
|
18
|
+
|
|
19
|
+
await instance.commandHandler.customCommands.create(
|
|
20
|
+
guild.id,
|
|
21
|
+
commandName,
|
|
22
|
+
description,
|
|
23
|
+
response
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return `Custom command "${commandName}" has been created!`
|
|
27
|
+
},
|
|
28
|
+
}
|