Potential slash-command compatibility, some code cleanup
parent
22581c242b
commit
f03a76897a
@ -0,0 +1,177 @@
|
|||||||
|
local discordia = require("discordia")
|
||||||
|
local endpoints = require('./endpoints')
|
||||||
|
local f = string.format
|
||||||
|
local AC = require('./ApplicationCommand')
|
||||||
|
local IA = require('./Interaction')
|
||||||
|
local client_m = discordia.Client
|
||||||
|
local guild_m = discordia.class.classes.Guild
|
||||||
|
local cache_m = discordia.class.classes.Cache
|
||||||
|
local enums = require('./enums')
|
||||||
|
|
||||||
|
local typeConverter = {
|
||||||
|
[enums.optionType.string] = function(val) return val end,
|
||||||
|
[enums.optionType.integer] = function(val) return val end,
|
||||||
|
[enums.optionType.boolean] = function(val) return val end,
|
||||||
|
[enums.optionType.user] = function(val, args) return args:getMember(val) end,
|
||||||
|
[enums.optionType.channel] = function(val, args) return args:getChannel(val) end,
|
||||||
|
[enums.optionType.role] = function(val, args) return args:getRole(val) end,
|
||||||
|
}
|
||||||
|
|
||||||
|
local subCommand = enums.optionType.subCommand
|
||||||
|
local subCommandGroup = enums.optionType.subCommandGroup
|
||||||
|
|
||||||
|
local function makeParams(data, guild, output)
|
||||||
|
output = output or {}
|
||||||
|
|
||||||
|
for k, v in ipairs(data) do
|
||||||
|
if v.type == subCommand or v.type == subCommandGroup then
|
||||||
|
local t = {}
|
||||||
|
output[v.name] = t
|
||||||
|
makeParams(v.options, guild, t)
|
||||||
|
else
|
||||||
|
output[v.name] = typeConverter[v.type](v.value, guild)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
function client_m:useSlashCommands()
|
||||||
|
self._slashCommandsInjected = true
|
||||||
|
|
||||||
|
function self._events.INTERACTION_CREATE(args, client)
|
||||||
|
local data = args.data
|
||||||
|
local cmd = client:getSlashCommand(data.id)
|
||||||
|
if not cmd then return client:warning('Uncached slash command (%s) on INTERACTION_CREATE', data.id) end
|
||||||
|
if data.name ~= cmd._name then return client:warning('Slash command %s "%s" name doesn\'t match with interaction response, got "%s"! Guild %s, channel %s, member %s', cmd._id, cmd._name, data.name, args.guild_id, args.channel_id, args.member.user.id) end
|
||||||
|
local ia = IA(args, client)
|
||||||
|
local params = makeParams(data.options, ia.guild)
|
||||||
|
local cb = cmd._callback
|
||||||
|
if not cb then return client:warning('Unhandled slash command interaction: %s "%s" (%s)!', cmd._id, cmd._name, cmd._guild and "Guild " .. cmd._guild.id or "Global") end
|
||||||
|
cb(ia, params, cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:once("ready", function()
|
||||||
|
local id = self:getApplicationInformation().id
|
||||||
|
self._slashid = id
|
||||||
|
self._globalCommands = {}
|
||||||
|
self._guildCommands = {}
|
||||||
|
self:getSlashCommands()
|
||||||
|
self:emit("slashCommandsReady")
|
||||||
|
end)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function client_m:slashCommand(data)
|
||||||
|
local found
|
||||||
|
|
||||||
|
if not self._globalCommands then
|
||||||
|
self:getSlashCommands()
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local name = data.name
|
||||||
|
|
||||||
|
for _, v in pairs(self._globalCommands) do
|
||||||
|
if v._name == name then
|
||||||
|
found = v
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmd = AC(data, self)
|
||||||
|
|
||||||
|
if found then
|
||||||
|
if not found:_compare(cmd) then
|
||||||
|
found:_merge(cmd)
|
||||||
|
elseif not found._callback then
|
||||||
|
found._callback = cmd._callback
|
||||||
|
end
|
||||||
|
|
||||||
|
return found
|
||||||
|
else
|
||||||
|
if cmd:publish() then
|
||||||
|
self._globalCommands:_insert(cmd)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
end
|
||||||
|
|
||||||
|
function guild_m:slashCommand(data)
|
||||||
|
local found
|
||||||
|
|
||||||
|
if not self._slashCommands then
|
||||||
|
self:getSlashCommands()
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local name = data.name
|
||||||
|
|
||||||
|
for _, v in pairs(self._slashCommands) do
|
||||||
|
if v._name == name then
|
||||||
|
found = v
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmd = AC(data, self)
|
||||||
|
|
||||||
|
if found then
|
||||||
|
if not found:_compare(cmd) then
|
||||||
|
found:_merge(cmd)
|
||||||
|
elseif not found._callback then
|
||||||
|
found._callback = cmd._callback
|
||||||
|
end
|
||||||
|
|
||||||
|
return found
|
||||||
|
else
|
||||||
|
if cmd:publish() then
|
||||||
|
self._slashCommands:_insert(cmd)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
end
|
||||||
|
|
||||||
|
function client_m:getSlashCommands()
|
||||||
|
local list, err = self._api:request('GET', f(endpoints.COMMANDS, self._slashid))
|
||||||
|
if not list then return nil, err end
|
||||||
|
local cache = cache_m(list, AC, self)
|
||||||
|
self._globalCommands = cache
|
||||||
|
|
||||||
|
return cache
|
||||||
|
end
|
||||||
|
|
||||||
|
function guild_m:getSlashCommands()
|
||||||
|
local list, err = self.client._api:request('GET', f(endpoints.COMMANDS_GUILD, self.client._slashid, self.id))
|
||||||
|
if not list then return nil, err end
|
||||||
|
local cache = cache_m(list, AC, self)
|
||||||
|
self._slashCommands = cache
|
||||||
|
self.client._guildCommands[self] = cache
|
||||||
|
|
||||||
|
return cache
|
||||||
|
end
|
||||||
|
|
||||||
|
function client_m:getSlashCommand(id)
|
||||||
|
if not self._globalCommands then
|
||||||
|
self:getSlashCommands()
|
||||||
|
end
|
||||||
|
|
||||||
|
local g = self._globalCommands:get(id)
|
||||||
|
if g then return g end
|
||||||
|
|
||||||
|
for _, v in pairs(self._guildCommands) do
|
||||||
|
g = v:get(id)
|
||||||
|
if g then return g end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
@ -0,0 +1,283 @@
|
|||||||
|
local discordia = require("discordia")
|
||||||
|
local endpoints = require('./endpoints')
|
||||||
|
local f = string.format
|
||||||
|
local Snowflake_m = discordia.class.classes.Snowflake
|
||||||
|
local AC, ACgetters = discordia.class('ApplicationCommand', Snowflake_m)
|
||||||
|
|
||||||
|
local function recursiveOptionsMap(t)
|
||||||
|
local map = {}
|
||||||
|
|
||||||
|
for _, v in ipairs(t) do
|
||||||
|
local name = string.lower(v.name)
|
||||||
|
v.name = name
|
||||||
|
map[name] = v
|
||||||
|
|
||||||
|
if v.options then
|
||||||
|
v.mapoptions = recursiveOptionsMap(v.options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return map
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:__init(data, parent)
|
||||||
|
self._id = data.id
|
||||||
|
self._parent = parent
|
||||||
|
self._name = data.name
|
||||||
|
self._description = data.description
|
||||||
|
self._default_permission = data.default_permission
|
||||||
|
self._version = data.version
|
||||||
|
self._callback = data.callback
|
||||||
|
self._guild = parent._id and parent
|
||||||
|
|
||||||
|
if not self._options then
|
||||||
|
self._options = data.options or {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:publish()
|
||||||
|
if self._id then return self:edit() end
|
||||||
|
local g = self._guild
|
||||||
|
|
||||||
|
if not g then
|
||||||
|
local res, err = self.client._api:request('POST', f(endpoints.COMMANDS, self.client._slashid), {
|
||||||
|
name = self._name,
|
||||||
|
description = self._description,
|
||||||
|
options = self._options,
|
||||||
|
default_permission = self._default_permission
|
||||||
|
})
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
return nil, err
|
||||||
|
else
|
||||||
|
self._id = res.id
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local res, err = self.client._api:request('POST', f(endpoints.COMMANDS_GUILD, self.client._slashid, g._id), {
|
||||||
|
name = self._name,
|
||||||
|
description = self._description,
|
||||||
|
options = self._options,
|
||||||
|
default_permission = self._default_permission
|
||||||
|
})
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
return nil, err
|
||||||
|
else
|
||||||
|
self._id = res.id
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:edit()
|
||||||
|
local g = self._guild
|
||||||
|
|
||||||
|
if not g then
|
||||||
|
local res, err = self.client._api:request('PATCH', f(endpoints.COMMANDS_MODIFY, self.client._slashid, self._id), {
|
||||||
|
name = self._name,
|
||||||
|
description = self._description,
|
||||||
|
options = self._options,
|
||||||
|
default_permission = self._default_permission
|
||||||
|
})
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
return nil, err
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local res, err = self.client._api:request('PATCH', f(endpoints.COMMANDS_MODIFY_GUILD, self.client._slashid, g._id, self._id), {
|
||||||
|
name = self._name,
|
||||||
|
description = self._description,
|
||||||
|
options = self._options,
|
||||||
|
default_permission = self._default_permission
|
||||||
|
})
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
return nil, err
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:setName(name)
|
||||||
|
self._name = name
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:setDescription(description)
|
||||||
|
self._description = description
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:setOptions(options)
|
||||||
|
self._options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:setCallback(callback)
|
||||||
|
self._callback = callback
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:delete()
|
||||||
|
local g = self._guild
|
||||||
|
|
||||||
|
if not g then
|
||||||
|
self.client._api:request('DELETE', f(endpoints.COMMANDS_MODIFY, self.client._slashid, self._id))
|
||||||
|
self.client._globalCommands:_delete(self._id)
|
||||||
|
else
|
||||||
|
self.client._api:request('DELETE', f(endpoints.COMMANDS_MODIFY_GUILD, self.client._slashid, g._id, self._id))
|
||||||
|
g._slashCommands:_delete(self._id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:getPermissions(g)
|
||||||
|
g = self._guild or g
|
||||||
|
|
||||||
|
if not g then
|
||||||
|
error("Guild is required")
|
||||||
|
end
|
||||||
|
|
||||||
|
local stat, err = self.client._api:request('GET', f(endpoints.COMMAND_PERMISSIONS_MODIFY, self.client._slashid, g._id, self._id))
|
||||||
|
|
||||||
|
if stat then
|
||||||
|
return stat.permissions
|
||||||
|
else
|
||||||
|
return stat, err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:addPermission(perm, g)
|
||||||
|
g = self._guild or g
|
||||||
|
|
||||||
|
if not g then
|
||||||
|
error("Guild is required")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self._permissions then
|
||||||
|
self._permissions = self:getPermissions(g) or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in ipairs(self._permissions) do
|
||||||
|
if v.id == perm.id and v.type == perm.type then
|
||||||
|
if v.permission == perm.permission then return end
|
||||||
|
self._permissions[k] = perm
|
||||||
|
goto found
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
self._permissions[#self._permissions + 1] = perm
|
||||||
|
end
|
||||||
|
|
||||||
|
::found::
|
||||||
|
|
||||||
|
return self.client._api:request('PUT', f(endpoints.COMMAND_PERMISSIONS_MODIFY, self.client._slashid, g._id, self._id), {
|
||||||
|
permissions = self._permissions
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:removePermission(perm, g)
|
||||||
|
g = self._guild or g
|
||||||
|
|
||||||
|
if not g then
|
||||||
|
error("Guild is required")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self._permissions then
|
||||||
|
self._permissions = self:getPermissions(g) or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in ipairs(self._permissions) do
|
||||||
|
if v.id == perm.id and v.type == perm.type then
|
||||||
|
table.remove(self._permissions, k)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.client._api:request('PUT', f(endpoints.COMMAND_PERMISSIONS_MODIFY, self.client._slashid, g._id, self._id), {
|
||||||
|
permissions = self._permissions
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function recursiveCompare(a, b, checked)
|
||||||
|
checked = checked or {}
|
||||||
|
if checked[a] or checked[b] then return true end
|
||||||
|
local inner_checked = {}
|
||||||
|
|
||||||
|
for k, v in pairs(a) do
|
||||||
|
if type(v) == "table" and type(b[k]) == "table" then
|
||||||
|
if not recursiveCompare(v, b[k], checked) then return false end
|
||||||
|
elseif v ~= b[k] then
|
||||||
|
print("k: ", k, "a[k]:", v, "b[k]: ", b[k])
|
||||||
|
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
inner_checked[k] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(b) do
|
||||||
|
if inner_checked[k] then
|
||||||
|
goto skip
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(v) == "table" and type(a[k]) == "table" then
|
||||||
|
if not recursiveCompare(v, a[k], checked) then return false end
|
||||||
|
elseif v ~= a[k] then
|
||||||
|
print("k: ", k, "a[k]:", a[k], "b[k]: ", v)
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
::skip::
|
||||||
|
end
|
||||||
|
|
||||||
|
checked[a], checked[b] = true, true
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:_compare(cmd)
|
||||||
|
if self._name ~= cmd._name or self._description ~= cmd._description or self._default_permission ~= cmd._default_permission then return false end
|
||||||
|
if not self._options and cmd._options then return false end
|
||||||
|
if not recursiveCompare(self._options, cmd._options) then return false end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function AC:_merge(cmd)
|
||||||
|
self._name = cmd._name
|
||||||
|
self._description = cmd._description
|
||||||
|
self._options = cmd._options
|
||||||
|
self._callback = cmd._callback
|
||||||
|
self._default_permission = cmd._default_permission
|
||||||
|
self:edit()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ACgetters:name()
|
||||||
|
return self._name
|
||||||
|
end
|
||||||
|
|
||||||
|
function ACgetters:description()
|
||||||
|
return self._description
|
||||||
|
end
|
||||||
|
|
||||||
|
function ACgetters:options()
|
||||||
|
return self._options
|
||||||
|
end
|
||||||
|
|
||||||
|
function ACgetters:guild()
|
||||||
|
return self._guild
|
||||||
|
end
|
||||||
|
|
||||||
|
function ACgetters:callback()
|
||||||
|
return self._callback
|
||||||
|
end
|
||||||
|
|
||||||
|
function ACgetters:version()
|
||||||
|
return self._version
|
||||||
|
end
|
||||||
|
|
||||||
|
return AC
|
@ -0,0 +1,121 @@
|
|||||||
|
local discordia = require("discordia")
|
||||||
|
local endpoints = require('./endpoints')
|
||||||
|
local enums = require('./enums')
|
||||||
|
local f = string.format
|
||||||
|
local Snowflake_m = discordia.class.classes.Snowflake
|
||||||
|
local IA, IAgetters = discordia.class('Interaction', Snowflake_m)
|
||||||
|
|
||||||
|
function IA:__init(data, parent)
|
||||||
|
self._id = data.id
|
||||||
|
self._parent = parent
|
||||||
|
self._type = data.type
|
||||||
|
self._token = data.token
|
||||||
|
self._version = data.version
|
||||||
|
local g = parent:getGuild(data.guild_id)
|
||||||
|
if not g then return parent:warning('Uncached Guild (%s) on INTERACTION_CREATE', data.guild_id) end
|
||||||
|
self._guild = g
|
||||||
|
self._channel = g:getChannel(data.channel_id)
|
||||||
|
self._member = g:getMember(data.member.user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:createResponse(type, data)
|
||||||
|
self._type = type
|
||||||
|
|
||||||
|
return self._parent._api:request('POST', f(endpoints.INTERACTION_RESPONSE, self._id, self._token), {
|
||||||
|
type = type,
|
||||||
|
data = data,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local deferredChannelMessageWithSource = enums.interactionResponseType.deferredChannelMessageWithSource
|
||||||
|
local channelMessageWithSource = enums.interactionResponseType.channelMessageWithSource
|
||||||
|
|
||||||
|
function IA:ack()
|
||||||
|
return self:createResponse(deferredChannelMessageWithSource)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:reply(data, private)
|
||||||
|
if type(data) == "string" then
|
||||||
|
data = {
|
||||||
|
content = data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if private then
|
||||||
|
data.flags = 64
|
||||||
|
end
|
||||||
|
|
||||||
|
return self:createResponse(channelMessageWithSource, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:update(data)
|
||||||
|
if type(data) == "string" then
|
||||||
|
data = {
|
||||||
|
content = data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return self._parent._api:request('PATCH', f(endpoints.INTERACTION_RESPONSE_MODIFY, self._parent._slashid, self._token), data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:delete()
|
||||||
|
return self._parent._api:request('DELETE', f(endpoints.INTERACTION_RESPONSE_MODIFY, self._parent._slashid, self._token))
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:followUp(data, private)
|
||||||
|
if type(data) == "string" then
|
||||||
|
data = {
|
||||||
|
content = data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if private then
|
||||||
|
if self._type == deferredChannelMessageWithSource then
|
||||||
|
private = false
|
||||||
|
else
|
||||||
|
data.flags = 64
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local res = self._parent._api:request('POST', f(endpoints.INTERACTION_FOLLOWUP_CREATE, self._parent._slashid, self._token), data)
|
||||||
|
|
||||||
|
if res.id then
|
||||||
|
local msg
|
||||||
|
|
||||||
|
if not private then
|
||||||
|
msg = self._channel:getMessage(res.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
return res.id, msg, res
|
||||||
|
end
|
||||||
|
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:updateFollowUp(id, data)
|
||||||
|
if type(data) == "string" then
|
||||||
|
data = {
|
||||||
|
content = data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return self._parent._api:request('PATCH', f(endpoints.INTERACTION_FOLLOWUP_MODIFY, self._parent._slashid, self._token, id), data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IA:deleteFollowUp(id)
|
||||||
|
return self._parent._api:request('DELETE', f(endpoints.INTERACTION_FOLLOWUP_MODIFY, self._parent._slashid, self._token, id))
|
||||||
|
end
|
||||||
|
|
||||||
|
function IAgetters:guild()
|
||||||
|
return self._guild
|
||||||
|
end
|
||||||
|
|
||||||
|
function IAgetters:channel()
|
||||||
|
return self._channel
|
||||||
|
end
|
||||||
|
|
||||||
|
function IAgetters:member()
|
||||||
|
return self._member
|
||||||
|
end
|
||||||
|
|
||||||
|
return IA
|
@ -0,0 +1,227 @@
|
|||||||
|
local optionMeta = {}
|
||||||
|
optionMeta.__index = optionMeta
|
||||||
|
|
||||||
|
function optionMeta:option(name, description, type, required)
|
||||||
|
if not name then
|
||||||
|
error("Name is required")
|
||||||
|
elseif not description then
|
||||||
|
error("Description is required")
|
||||||
|
elseif not type then
|
||||||
|
error("Type is required")
|
||||||
|
elseif #name == 0 or #name > 32 then
|
||||||
|
error("Must be between 1 and 32 in length")
|
||||||
|
elseif string.find(name, "^[^%w_-]$") then
|
||||||
|
error("The name should match ^[\\w-]{1,32}$ pattern")
|
||||||
|
elseif #description == 0 or #description > 100 then
|
||||||
|
error("Must be between 1 and 100 in length")
|
||||||
|
elseif type < 1 or type > 8 then
|
||||||
|
error("Value type must be between 1 and 8 (See ApplicationCommandOptionType)")
|
||||||
|
end
|
||||||
|
|
||||||
|
local ctnr = self[1]
|
||||||
|
local selfType = ctnr.type
|
||||||
|
|
||||||
|
if not self[2] then
|
||||||
|
if selfType <= 2 then
|
||||||
|
if (selfType == 1 and type <= 2) or (selfType == 2 and type == 2) then
|
||||||
|
error("Nesting of sub-commands is unsupported at this time")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("Sub-options cannot be configured for this type of option")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = setmetatable({
|
||||||
|
parent = self,
|
||||||
|
{
|
||||||
|
name = name,
|
||||||
|
description = description,
|
||||||
|
type = type,
|
||||||
|
}
|
||||||
|
}, optionMeta)
|
||||||
|
|
||||||
|
if not ctnr.options then
|
||||||
|
ctnr.options = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
ctnr.options[#ctnr.options + 1] = t
|
||||||
|
|
||||||
|
if required then
|
||||||
|
t:required()
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
function optionMeta:suboption(name, description)
|
||||||
|
return self:option(name, description, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function optionMeta:group(name, description)
|
||||||
|
return self:option(name, description, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function optionMeta:required(no)
|
||||||
|
local ctnr = self[1]
|
||||||
|
local type = ctnr.type
|
||||||
|
|
||||||
|
if type <= 2 then
|
||||||
|
error("Required cannot be configured for this type of option")
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, v in ipairs(self.parent[1].options) do
|
||||||
|
if not v.required then
|
||||||
|
error("Required options must be placed before non-required options")
|
||||||
|
end
|
||||||
|
|
||||||
|
if v == self then break end
|
||||||
|
end
|
||||||
|
|
||||||
|
ctnr.required = not no
|
||||||
|
end
|
||||||
|
|
||||||
|
-- function optionMeta:default(no)
|
||||||
|
-- local ctnr = self[1]
|
||||||
|
-- local type = ctnr.type
|
||||||
|
-- if type <= 2 then
|
||||||
|
-- error("Default cannot be configured for this type of option")
|
||||||
|
-- end
|
||||||
|
-- if not self[1].required then
|
||||||
|
-- error("Default cannot be configured with required = false")
|
||||||
|
-- end
|
||||||
|
-- for _, v in ipairs(self.parent[1].options) do
|
||||||
|
-- if v[1].default then
|
||||||
|
-- error("There can be 1 default option within command, sub-command, and sub-command group options")
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- ctnr.default = not no
|
||||||
|
-- end
|
||||||
|
function optionMeta:choices(...)
|
||||||
|
local ctnr = self[1]
|
||||||
|
local opttype = ctnr.type
|
||||||
|
local acceptedType
|
||||||
|
|
||||||
|
if opttype == 3 then
|
||||||
|
acceptedType = "string"
|
||||||
|
elseif opttype == 4 then
|
||||||
|
acceptedType = "number"
|
||||||
|
else
|
||||||
|
error("Choices cannot be configured for this type of option")
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = {}
|
||||||
|
ctnr.choices = t
|
||||||
|
|
||||||
|
for i = 1, select("#", ...) do
|
||||||
|
local v = select(i, ...)
|
||||||
|
|
||||||
|
if type(v) == acceptedType then
|
||||||
|
t[i] = {
|
||||||
|
name = tostring(v),
|
||||||
|
value = v
|
||||||
|
}
|
||||||
|
else
|
||||||
|
t[i] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function optionMeta:finish()
|
||||||
|
local t = {}
|
||||||
|
|
||||||
|
for k, v in pairs(self[1]) do
|
||||||
|
t[k] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
if t.options then
|
||||||
|
local options = {}
|
||||||
|
|
||||||
|
for k, v in ipairs(t.options) do
|
||||||
|
options[k] = v:finish()
|
||||||
|
end
|
||||||
|
|
||||||
|
t.options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local commandMeta = {}
|
||||||
|
commandMeta.__index = commandMeta
|
||||||
|
commandMeta.option = optionMeta.option
|
||||||
|
commandMeta.finish = optionMeta.finish
|
||||||
|
commandMeta.suboption = optionMeta.suboption
|
||||||
|
commandMeta.group = optionMeta.group
|
||||||
|
|
||||||
|
function commandMeta:disableForEveryone(no)
|
||||||
|
if not no then
|
||||||
|
no = false
|
||||||
|
end
|
||||||
|
|
||||||
|
self[1].default_permission = no
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function commandMeta:callback(cb)
|
||||||
|
self[1].callback = cb
|
||||||
|
end
|
||||||
|
|
||||||
|
local function new(name, description, cb)
|
||||||
|
if not name then
|
||||||
|
error("Name is required")
|
||||||
|
elseif not description then
|
||||||
|
error("Description is required")
|
||||||
|
elseif #name == 0 or #name > 32 then
|
||||||
|
error("Must be between 1 and 32 in length")
|
||||||
|
elseif string.find(name, "^[^%w_-]$") then
|
||||||
|
error("The name should match ^[\\w-]{1,32}$ pattern")
|
||||||
|
elseif #description == 0 or #description > 100 then
|
||||||
|
error("Must be between 1 and 100 in length")
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable({
|
||||||
|
{
|
||||||
|
name = name,
|
||||||
|
description = description,
|
||||||
|
options = {},
|
||||||
|
default_permission = true,
|
||||||
|
callback = cb
|
||||||
|
},
|
||||||
|
true
|
||||||
|
}, commandMeta)
|
||||||
|
end
|
||||||
|
|
||||||
|
local discordia = require("discordia")
|
||||||
|
local enums = require("./enums")
|
||||||
|
local enum_user = enums.applicationCommandPermissionType.user
|
||||||
|
local enum_role = enums.applicationCommandPermissionType.role
|
||||||
|
|
||||||
|
local function perm(obj, allow, _type)
|
||||||
|
if type(obj) == "string" then
|
||||||
|
if not _type then
|
||||||
|
error("Type required")
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
id = obj,
|
||||||
|
type = _type,
|
||||||
|
permission = allow and true or false
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = discordia.class.type(obj)
|
||||||
|
|
||||||
|
if t == "Member" or t == "User" then
|
||||||
|
_type = enum_user
|
||||||
|
elseif t == "Role" then
|
||||||
|
_type = enum_role
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
id = obj.id,
|
||||||
|
type = _type,
|
||||||
|
permission = allow and true or false
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {new, perm}
|
@ -0,0 +1,12 @@
|
|||||||
|
return {
|
||||||
|
COMMANDS = "/applications/%s/commands",
|
||||||
|
COMMANDS_GUILD = "/applications/%s/guilds/%s/commands",
|
||||||
|
COMMANDS_MODIFY = "/applications/%s/commands/%s",
|
||||||
|
COMMANDS_MODIFY_GUILD = "/applications/%s/guilds/%s/commands/%s",
|
||||||
|
COMMAND_PERMISSIONS = "/applications/%s/guilds/%s/commands/permissions",
|
||||||
|
COMMAND_PERMISSIONS_MODIFY = "/applications/%s/guilds/%s/commands/%s/permissions",
|
||||||
|
INTERACTION_RESPONSE = "/interactions/%s/%s/callback",
|
||||||
|
INTERACTION_RESPONSE_MODIFY = "/webhooks/%s/%s/messages/@original",
|
||||||
|
INTERACTION_FOLLOWUP_CREATE = "/webhooks/%s/%s",
|
||||||
|
INTERACTION_FOLLOWUP_MODIFY = "/webhooks/%s/%s/messages/%s"
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
local enum = require('discordia').enums.enum
|
||||||
|
|
||||||
|
return {
|
||||||
|
optionType = enum({
|
||||||
|
subCommand = 1,
|
||||||
|
subCommandGroup = 2,
|
||||||
|
string = 3,
|
||||||
|
integer = 4,
|
||||||
|
boolean = 5,
|
||||||
|
user = 6,
|
||||||
|
channel = 7,
|
||||||
|
role = 8
|
||||||
|
}),
|
||||||
|
interactionType = enum({
|
||||||
|
ping = 1,
|
||||||
|
applicationCommand = 2
|
||||||
|
}),
|
||||||
|
interactionResponseType = enum({
|
||||||
|
pong = 1,
|
||||||
|
channelMessageWithSource = 4,
|
||||||
|
deferredChannelMessageWithSource = 5
|
||||||
|
}),
|
||||||
|
applicationCommandPermissionType = enum({
|
||||||
|
role = 1,
|
||||||
|
user = 2,
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
require("./Application")
|
||||||
|
|
||||||
|
local ret = {
|
||||||
|
enums = require("./enums")
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.constructor = function()
|
||||||
|
ret.new, ret.permission = unpack(require("./constructor"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return ret
|
@ -0,0 +1,15 @@
|
|||||||
|
return {
|
||||||
|
name = 'GitSparTV/discordia-slash',
|
||||||
|
description = 'Discordia 2.0 slash commands extension',
|
||||||
|
version = '2.0.0',
|
||||||
|
homepage = 'https://github.com/GitSparTV/discordia-slash',
|
||||||
|
dependencies = {
|
||||||
|
'SinisterRectus/discordia@2.8.4',
|
||||||
|
},
|
||||||
|
tags = {'discord', 'slash', 'discordia'},
|
||||||
|
license = 'MIT',
|
||||||
|
author = 'Spar',
|
||||||
|
files = {
|
||||||
|
'**.lua',
|
||||||
|
},
|
||||||
|
}
|
@ -1,3 +1,17 @@
|
|||||||
Hello!
|
```fix
|
||||||
Line 2
|
Basic functions
|
||||||
Line 3!
|
---------------
|
||||||
|
-ping
|
||||||
|
Pong!
|
||||||
|
-roll
|
||||||
|
Rolls a d20
|
||||||
|
-time
|
||||||
|
Displays the time in military time, as if you were in chicago
|
||||||
|
-help
|
||||||
|
^-^
|
||||||
|
Basic Information
|
||||||
|
-----------------
|
||||||
|
All functions start with '!' though this may change in the future
|
||||||
|
Under construction! More or less from scratch(Only just got basic I/O working!)
|
||||||
|
May have secret functions!
|
||||||
|
```
|
||||||
|
@ -1 +1 @@
|
|||||||
{"873255296024322059":{"timestamp":1628279979,"owner":{"username":"team872299874857676820","id":"872299874857676820","public_flags":1024,"flags":1024,"discriminator":"0000","avatar":null},"shards":1},"url":"wss://gateway.discord.gg"}
|
{"873255296024322059":{"timestamp":1628283774,"owner":{"discriminator":"0000","avatar":null,"id":"872299874857676820","flags":1024,"public_flags":1024,"username":"team872299874857676820"},"shards":1},"url":"wss://gateway.discord.gg"}
|
Loading…
Reference in New Issue