Yessiest
2 years ago
30 changed files with 307 additions and 1559 deletions
-
2bot.lua
-
BINlibraries/.tasklib.lua.swp
-
151libraries/air.lua
-
4libraries/classes/.test/test.lua
-
1libraries/classes/.test/tty-colors.lua
-
20libraries/classes/command-acl.lua
-
0libraries/classes/command-class.lua
-
9libraries/classes/command-handler.lua
-
56libraries/classes/command.lua
-
6libraries/classes/plugin-handler.lua
-
9libraries/classes/server-handler.lua
-
50libraries/cron.lua
-
26libraries/logging.lua
-
44libraries/string_parse.lua
-
1plugins/cron/help.lua
-
37plugins/cron/init.lua
-
2plugins/esolang/init.lua
-
5plugins/help/init.lua
-
11plugins/meta/help.lua
-
93plugins/meta/init.lua
-
3plugins/plugins/init.lua
-
17plugins/reactions/init.lua
-
3plugins/roledefaults/init.lua
-
5plugins/security/init.lua
-
2plugins/tools/help.lua
-
9plugins/tools/init.lua
-
478todo-stuff/enforcer/init.lua
-
340todo-stuff/reactions/init.lua
-
120todo-stuff/settings/init.lua
-
362todo-stuff/tasks/init.lua
@ -1 +0,0 @@ |
|||
../../tty-colors.lua |
@ -0,0 +1,26 @@ |
|||
local logging_facilities = { |
|||
["ALIAS"] = "0;32", |
|||
["REACTIONS"] = "0;32", |
|||
["SERVER"] = "1;34", |
|||
["ERROR"] = "1;31", |
|||
["WARNING"] = "1;33" |
|||
} |
|||
local clear = "\27[0m" |
|||
local concat = function(tab,separator) |
|||
local text = "" |
|||
local separator = separator or "\9" |
|||
for k,v in pairs(tab) do |
|||
text = text..tostring(v)..separator |
|||
end |
|||
return text:sub(1,-1-separator:len()) |
|||
end |
|||
return function(facility, ...) |
|||
local effect = "\27[" |
|||
if logging_facilities[facility] then |
|||
effect = effect..logging_facilities[facility].."m" |
|||
else |
|||
effect = effect.."1m" |
|||
end |
|||
print(os.date("%Y-%m-%d %H:%M:%S | ")..effect.."["..facility.."]"..clear.."\9| "..concat({...})) |
|||
end |
|||
|
@ -0,0 +1,44 @@ |
|||
return function(text,custom_strings) |
|||
local delimiters = custom_strings or "[\"'/]" |
|||
-- Find 2 string delimiters. |
|||
-- Partition text into before and after if the string is empty |
|||
-- Partition text into before, string and after if the string isn't empty |
|||
local strings = {text} |
|||
while strings[#strings]:match(delimiters) do |
|||
local string = strings[#strings] |
|||
-- Opening character for a string |
|||
local open_pos = string:find(delimiters) |
|||
local open_char = string:sub(open_pos,open_pos) |
|||
if strings[#strings]:sub(open_pos+1,open_pos+1) == open_char then |
|||
-- Empty string |
|||
local text_before = string:sub(1,open_pos-1) |
|||
local text_after = string:sub(open_pos+2,-1) |
|||
strings[#strings] = text_before |
|||
table.insert(strings,open_char..open_char) |
|||
table.insert(strings,text_after) |
|||
else |
|||
-- Non-empty string |
|||
local text_before = string:sub(1,open_pos-1) |
|||
local _,closing_position = string:sub(open_pos,-1):find("[^\\]"..open_char) |
|||
if not closing_position then |
|||
break |
|||
else |
|||
closing_position = closing_position+open_pos-1 |
|||
end |
|||
local text_string = string:sub(open_pos,closing_position) |
|||
local text_after = string:sub(closing_position+1,-1) |
|||
strings[#strings] = text_before |
|||
table.insert(strings,text_string) |
|||
table.insert(strings,text_after) |
|||
end |
|||
end |
|||
for k,v in pairs(strings) do |
|||
if v:len() == 0 then |
|||
table.remove(strings,k) |
|||
end |
|||
end |
|||
return strings |
|||
-- P.S: This one is the best one i've written. Sure it looks clunky, but it |
|||
-- does exactly what I expect it to do - handle cases when there are string |
|||
-- delimiters inside other strings. Lovely. Also kinda horrifying. |
|||
end |
@ -1,478 +0,0 @@ |
|||
--TODO: Add domain-specific manuals, Document |
|||
local air = require("air") |
|||
local json = require("json") |
|||
local file = require("file") |
|||
file.activate_json(json) |
|||
local segment = {} |
|||
segment.setnames = {} |
|||
segment.name = "enforcer" |
|||
segment.settings = { |
|||
automod = { |
|||
list = { |
|||
|
|||
}, |
|||
status = false, |
|||
warn_limit = 3 |
|||
} |
|||
} |
|||
|
|||
if globals.enofrcer then |
|||
if globals.enforcer.setnames then |
|||
segment.setnames = globals.enforcer.setnames |
|||
end |
|||
if globals.enforcer.settings then |
|||
segment.settings = global.enforcer.settings |
|||
end |
|||
end |
|||
segment.warns = file.readJSON("./servers/"..id.."/warns.json",{}) |
|||
|
|||
events:on("serverSaveConfig",function() |
|||
if not globals.enforcer then |
|||
globals.enforcer = {} |
|||
end |
|||
globals.enforcer.setnames = segment.setnames |
|||
globals.enforcer.settings = segment.settings |
|||
file.writeJSON("./servers/"..id.."/warns.json",segment.warns) |
|||
end) |
|||
|
|||
local warn = function(ID,reason) |
|||
local guild = client:getGuild(id) |
|||
local member = guild:getMember(tostring(ID)) |
|||
if not segment.warns[tostring(ID)] then segment.warns[tostring(ID)] = {} end |
|||
table.insert(segment.warns[tostring(ID)],1,reason) |
|||
if segment.settings.warn_limit and (#segment.warns[tostring(ID)] >= segment.settings.warn_limit) and guild:getMember(tostring(ID)) then |
|||
if segment.settings.warn_punishment == "kick" then |
|||
member:kick("Warning quota exceeded.") |
|||
elseif segment.settings.warn_punishment == "ban" then |
|||
member:ban("Warning quota exceeded.",segment.settings.ban_days) |
|||
end |
|||
end |
|||
_ = (client:getUser(tostring(ID)) and client:getUser(tostring(ID)):send("__You have been warned.__\nReason: "..reason)) |
|||
signals:emit("warn",function(args) |
|||
if args[1] and member.name:find(args[1],1,true) then |
|||
return true |
|||
elseif not args[1] then |
|||
return true |
|||
else |
|||
return false |
|||
end |
|||
end,{ |
|||
user = member.id, |
|||
name = member.name |
|||
}) |
|||
end |
|||
|
|||
segment.commands = { |
|||
["change-name"] = { |
|||
help = {embed = { |
|||
title = "Enforce a name upon a specific user", |
|||
description = "Whenever the user attempts to change their name, it will be changed back", |
|||
fields = { |
|||
{name = "Usage: ",value = "change-name <user> <name>"}, |
|||
{name = "Perms: ",value = "manageNicknames"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageNicknames" |
|||
} |
|||
}, |
|||
args = { |
|||
"member", |
|||
"string" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
name = args[2] |
|||
args[1]:setNickname(name) |
|||
segment.setnames[tostring(args[1].id)] = name |
|||
msg:reply("Now assigning an enforced name upon "..args[1].name) |
|||
end |
|||
}, |
|||
["reset-name"] = { |
|||
help = {embed = { |
|||
title = "Stop enforcing a name upon a user", |
|||
description = "Reverses the effect of ``change-name``", |
|||
fields = { |
|||
{name = "Usage: ",value = "reset-name"}, |
|||
{name = "Perms: ",value = "manageNicknames"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageNicknames" |
|||
} |
|||
}, |
|||
args = { |
|||
"member" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if segment.setnames[tostring(args[1].id)] then |
|||
segment.setnames[tostring(args[1].id)] = nil |
|||
args[1]:setNickname(nil) |
|||
msg:reply("No longer tracking "..args[1].name) |
|||
else |
|||
msg:reply("This user haven't been assigned an enforced name") |
|||
end |
|||
end |
|||
}, |
|||
["wipe"] = { |
|||
help = {embed={ |
|||
title = "Wipe user messages", |
|||
description = "Searches and deletes all messages of a specific user in a specified range", |
|||
fields = { |
|||
{name = "Usage: ",value = "wipe-user <range> <user mention or id>"}, |
|||
{name = "Perms: ",value = "manageMessages"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageMessages" |
|||
} |
|||
}, |
|||
args = { |
|||
"number", |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if tonumber(args[1]) and tonumber(args[1]) > 101 then |
|||
msg:reply("Search limit is too high") |
|||
return |
|||
end |
|||
local messages = {} |
|||
msg.channel:getMessages(args[1]):forEach(function(v) messages[#messages+1] = v.id end) |
|||
msg.channel:bulkDelete(messages) |
|||
end |
|||
}, |
|||
["wipe-user"] = { |
|||
help = {embed={ |
|||
title = "Wipe user messages", |
|||
description = "Searches and deletes all messages of a specific user in a specified range", |
|||
fields = { |
|||
{name = "Usage: ",value = "wipe-user <range> <user mention or id>"}, |
|||
{name = "Perms: ",value = "manageMessages"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageMessages" |
|||
} |
|||
}, |
|||
args = { |
|||
"number", |
|||
"member" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if tonumber(args[1]) and tonumber(args[1]) > 101 then |
|||
msg:reply("Search limit is too high") |
|||
return |
|||
end |
|||
local messages = {} |
|||
local target = args[2].user |
|||
msg.channel:getMessages(args[1]):forEach(function(v) |
|||
if v.author.id == target.id then |
|||
messages[#messages+1] = v.id |
|||
end |
|||
end) |
|||
msg.channel:bulkDelete(messages) |
|||
end |
|||
}, |
|||
["wipe-pattern"] = { |
|||
help = {embed={ |
|||
title = "Wipe by pattern", |
|||
description = "Searches for a specific pattern in a range of messages, and wipes if certain conditions are met", |
|||
fields = { |
|||
{name = "Usage: ",value = "wipe-pattern <range> <pattern>"}, |
|||
{name = "Perms: ",value = "manageMessages"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageMessages" |
|||
} |
|||
}, |
|||
args = { |
|||
"number", |
|||
"string" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if tonumber(args[1]) and tonumber(args[1]) > 101 then |
|||
msg:reply("Search limit is too high") |
|||
return |
|||
end |
|||
local messages = {} |
|||
msg.channel:getMessages(args[1]):forEach(function(v) |
|||
if v.content:find(args[2],1,true) then |
|||
messages[#messages+1] = v.id |
|||
end |
|||
end) |
|||
msg.channel:bulkDelete(messages) |
|||
end |
|||
}, |
|||
["kick"] = { |
|||
help = {embed={ |
|||
title = "Kick a member", |
|||
description = "Self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "kick <member> [<reason>]"}, |
|||
{name = "Perms: ",value= "kickMembers"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"kickMembers" |
|||
} |
|||
}, |
|||
args = { |
|||
"member" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local member = args[1] |
|||
signals:emit("kick",function(args) |
|||
if args[1] and member.name:find(args[1],1,true) then |
|||
return true |
|||
elseif not args[1] then |
|||
return true |
|||
else |
|||
return false |
|||
end |
|||
end,{ |
|||
user = member.id, |
|||
name = member.name, |
|||
reason = args[2] |
|||
}) |
|||
member:kick(args[2]) |
|||
end |
|||
}, |
|||
["ban"] = { |
|||
help = {embed={ |
|||
title = "Ban a member", |
|||
description = "Self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "ban <member> [<reason> [<days>]]"}, |
|||
{name = "Perms: ",value= "banMembers"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"banMembers" |
|||
} |
|||
}, |
|||
args = { |
|||
"member" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local member = args[1] |
|||
signals:emit("kick",function(args) |
|||
if args[1] and member.name:find(args[1],1,true) then |
|||
return true |
|||
elseif not args[1] then |
|||
return true |
|||
else |
|||
return false |
|||
end |
|||
end,{ |
|||
user = member.id, |
|||
name = member.name, |
|||
reason = args[2], |
|||
days = args[3] |
|||
}) |
|||
member:ban(args[2],tonumber(args[3])) |
|||
end |
|||
}, |
|||
["purge"] = { |
|||
help = {embed={ |
|||
title = "Purge bot messages", |
|||
description = "If a number is provided, the bot will search through that amount of messages, or through 100 of them by default", |
|||
fields = { |
|||
{name = "Usage: ",value = "ban <member> [<reason> [<days>]]"}, |
|||
{name = "Perms: ",value= "manageMessages"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageMessages" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local messages = {} |
|||
if tonumber(args[1]) and tonumber(args[1]) > 101 then |
|||
msg:reply("Search limit is too high") |
|||
return |
|||
end |
|||
msg.channel:getMessages(tonumber(args[1]) or 100):forEach(function(v) |
|||
if (v.author.id == client.user.id) or (v.content:find(globals.prefix)==1) then |
|||
messages[#messages+1] = v.id |
|||
end |
|||
end) |
|||
msg.channel:bulkDelete(messages) |
|||
end |
|||
}, |
|||
["warn"] = { |
|||
help = {embed={ |
|||
title = "Warn a user", |
|||
descriptions = "Warnings by themselves don't do any punishment to the user, but they allow managing users", |
|||
fields = { |
|||
{name = "Usage: ",value = "warn <user> <reason>"}, |
|||
{name = "Perms: ",value = "kickMembers"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"kickMembers" |
|||
} |
|||
}, |
|||
args = { |
|||
"member", |
|||
"string" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local reason = table.concat(args," ",2) |
|||
warn(args[1].id,reason) |
|||
msg:reply({embed = { |
|||
title = "User "..args[1].name.." warned", |
|||
description = "Reason: ```"..reason.."```" |
|||
}}) |
|||
end |
|||
}, |
|||
["warns"] = { |
|||
help = {embed={ |
|||
title = "List warnings", |
|||
descriptions = "self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "warns <member> [<page>]"}, |
|||
{name = "Perms: ",value = "kickMembers"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"kickMembers" |
|||
} |
|||
}, |
|||
args = { |
|||
"member", |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local page = (tonumber(args[2]) or 1)-1 |
|||
local new_embed = { |
|||
title = "Warnings for "..args[1].name, |
|||
fields = {} |
|||
} |
|||
if page < 0 then |
|||
new_embed.description = "Page "..page.." not found, reverting to first page" |
|||
page = 0 |
|||
end |
|||
if segment.warns[tostring(args[1].id)] and #segment.warns[tostring(args[1].id)] > 0 then |
|||
for I = 1+(page*5),5+(page*5) do |
|||
local warn = segment.warns[tostring(args[1].id)][I] |
|||
if warn then |
|||
table.insert(new_embed.fields,{name = "ID: "..tostring(I),value = warn}) |
|||
end |
|||
end |
|||
msg:reply({embed = new_embed}) |
|||
else |
|||
msg:reply("This user has no warnings") |
|||
end |
|||
end |
|||
}, |
|||
["unwarn"] = { |
|||
help = {embed={ |
|||
title = "Revoke a warning issued to a user", |
|||
descriptions = "self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "unwarn <user> [<warn id>]"}, |
|||
{name = "Perms: ",value = "kickMembers"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"kickMembers" |
|||
} |
|||
}, |
|||
args = { |
|||
"member", |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local warn_id = (tonumber(args[2]) or 1) |
|||
if segment.warns[tostring(args[1].id)][warn_id] then |
|||
table.remove(segment.warns[tostring(args[1].id)],warn_id) |
|||
msg:reply("Revoked warning #"..warn_id) |
|||
else |
|||
msg:reply("No warning with id "..warn_id) |
|||
end |
|||
end |
|||
}, |
|||
["add-role"] = { |
|||
help = {embed={ |
|||
title = "Give some specific user a role", |
|||
descriptions = "self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "unwarn <member> <role>"}, |
|||
{name = "Perms: ",value = "manageRoles"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageRoles" |
|||
} |
|||
}, |
|||
args = { |
|||
"member", |
|||
"role" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
args[1]:addRole(tostring(args[2].id)) |
|||
end |
|||
}, |
|||
["remove-role"] = { |
|||
help = {embed={ |
|||
title = "Revoke a role from a user", |
|||
descriptions = "self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "remove-role <member> <role>"}, |
|||
{name = "Perms: ",value = "manageRoles"} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"manageRoles" |
|||
} |
|||
}, |
|||
args = { |
|||
"member", |
|||
"role" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
args[1]:removeRole(tostring(args[2].id)) |
|||
end |
|||
}, |
|||
} |
|||
|
|||
events:on("memberUpdate",function(member) |
|||
if segment.setnames[tostring(member.id)] and member.nickname ~= segment.setnames[tostring(member.id)] then |
|||
member:setNickname(segment.setnames[tostring(member.id)]) |
|||
end |
|||
end) |
|||
|
|||
--old automod code |
|||
--[[ |
|||
events:on("messageCreate",function(msg) |
|||
if segment.settings.automod.status then |
|||
local trigger = "" |
|||
for k,v in pairs(segment.settings.automod.list) do |
|||
if msg.content:find(v) and msg.author ~= client.user then |
|||
trigger = trigger..v.."," |
|||
end |
|||
end |
|||
if trigger ~= "" then |
|||
full_text,author = msg.content.."",msg.author |
|||
msg:delete() |
|||
msg.author:send("The words \""..trigger.."\" are banned on this server.\nThis is the text that these words were found in: ```"..full_text.."```") |
|||
if segment.settings.automod.punishment == "kick" then |
|||
msg.author:kick("Usage of banned words") |
|||
elseif segment.settings.automod.punishment == "warn" then |
|||
warn(msg.author.id,"Usage of banned words",msg.guild) |
|||
end |
|||
end |
|||
end |
|||
end) |
|||
]] |
|||
return segment |
@ -1,340 +0,0 @@ |
|||
local segment = {} |
|||
local emulate = require("emulate")({ |
|||
client = client, |
|||
discordia = discordia, |
|||
}) |
|||
local file = require("file") |
|||
file.activate_json(require("json")) |
|||
local guild = client:getGuild(id) |
|||
segment.pivots = file.readJSON("./servers/"..id.."/reactions.json",{}) |
|||
local getEmoji = function(id) |
|||
local emoji = guild:getEmoji(id:match("(%d+)[^%d]*$")) |
|||
if emoji then |
|||
return emoji |
|||
else |
|||
return id |
|||
end |
|||
end |
|||
|
|||
local function count(tab) |
|||
local n = 0 |
|||
for k,v in pairs(tab) do |
|||
n = n + 1 |
|||
end |
|||
return n |
|||
end |
|||
|
|||
segment.commands = { |
|||
["pivot"] = { |
|||
help = { |
|||
title = "Select a pivot message to manipulate", |
|||
description = "Pivot is like a message selector which allows easy reaction manipulations", |
|||
fields = { |
|||
{name = "Usage: ",value = "pivot <message link>"}, |
|||
{name = "Perms: ",valeu = "Administartor"} |
|||
} |
|||
}, |
|||
args = { |
|||
"messageLink" |
|||
}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if segment.pivot and count(segment.pivot.buttons) == 0 then |
|||
segment.pivots[segment.pivot.message] = nil |
|||
end |
|||
local message = args[1] |
|||
if not message then |
|||
msg:reply("Couldn't find message with id "..args[2]) |
|||
return nil |
|||
end |
|||
if not segment.pivots[message.id] then |
|||
segment.pivots[message.id] = {} |
|||
segment.pivots[message.id].message = message.id |
|||
segment.pivots[message.id].channel = message.channel.id |
|||
segment.pivots[message.id].buttons = {} |
|||
end |
|||
segment.pivot = segment.pivots[message.id] |
|||
msg:reply("Pivot message set to "..message.link) |
|||
end |
|||
}, |
|||
["role-toggle"] = { |
|||
help = { |
|||
title = "Add a simple role switch to the pivot", |
|||
description = "Note: you cannot assign more than one role to a single reaction", |
|||
fields = { |
|||
{name = "Usage: ",value = "role-toggle <emoji> <role ping or role id>"}, |
|||
{name = "Perms: ",value = "administrator"} |
|||
} |
|||
}, |
|||
args = { |
|||
"string", |
|||
"role", |
|||
}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if not segment.pivot then |
|||
msg:reply("Pivot not selected. Use "..globals.prefix.."pivot to select it and then try again") |
|||
return nil |
|||
end |
|||
local emoji = getEmoji(args[1]) |
|||
local channel = guild:getChannel(segment.pivot.channel) |
|||
if not channel then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local message = channel:getMessage(segment.pivot.message) |
|||
if not message then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local grabEmoji = function(reaction) |
|||
segment.pivot.buttons[tostring(reaction.emojiId or reaction.emojiName)] = { |
|||
type = "role-toggler", |
|||
role = tostring(args[2].id) |
|||
} |
|||
msg:reply("Role toggler added successfully") |
|||
end |
|||
message:removeReaction(emoji,client.user.id) |
|||
client:once("reactionAdd",grabEmoji) |
|||
if not message:addReaction(emoji) then |
|||
client:removeListener("reactionAdd",grabEmoji) |
|||
msg:reply("Couldn't add reaction - emoji might be invalid") |
|||
end |
|||
end |
|||
}, |
|||
["remove-reaction"] = { |
|||
help = { |
|||
title = "Remove a reaction from a pivot", |
|||
description = "If you don't specify a reaction to remove, the entire pivot for the message is removed automatically", |
|||
fields = { |
|||
{name = "Usage: ",value = "remove-reaction <emoji>"}, |
|||
{name = "Perms: ",value = "Administrator"} |
|||
} |
|||
}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local channel = guild:getChannel(segment.pivot.channel) |
|||
if not channel then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local message = channel:getMessage(segment.pivot.message) |
|||
if not message then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
if args[1] then |
|||
local emoji = getEmoji(args[1]) |
|||
message:removeReaction(emoji,client.user.id) |
|||
segment.pivot.buttons[((type(emoji) == "table") and emoji.id) or emoji] = nil |
|||
msg:reply("Action successfully removed") |
|||
else |
|||
message:clearReactions() |
|||
segment.pivots[tostring(message.id)] = nil |
|||
segment.pivot = nil |
|||
msg:reply("Pivot successfully removed") |
|||
end |
|||
end |
|||
}, |
|||
["toggle"] = { |
|||
help = { |
|||
title = "Add a toggle that runs specific commands", |
|||
description = "Note: you cannot assign more than one action to a single reaction \n``$user`` gets replaced with the id of the user that interacted with the reaction.", |
|||
fields = { |
|||
{name = "Usage: ",value = "toggle <emoji> <command-on> <command-off>"}, |
|||
{name = "Perms: ",value = "administrator"} |
|||
} |
|||
}, |
|||
args = { |
|||
"string", |
|||
"string", |
|||
"string", |
|||
}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if not segment.pivot then |
|||
msg:reply("Pivot not selected. Use "..globals.prefix.."pivot to select it and then try again") |
|||
return nil |
|||
end |
|||
local emoji = getEmoji(args[1]) |
|||
local channel = guild:getChannel(segment.pivot.channel) |
|||
if not channel then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local message = channel:getMessage(segment.pivot.message) |
|||
if not message then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local grabEmoji = function(reaction) |
|||
segment.pivot.buttons[tostring(reaction.emojiId or reaction.emojiName)] = { |
|||
type = "toggler", |
|||
on = args[2], |
|||
off = args[3], |
|||
} |
|||
msg:reply("Toggler added successfully") |
|||
end |
|||
message:removeReaction(emoji,client.user.id) |
|||
client:once("reactionAdd",grabEmoji) |
|||
if not message:addReaction(emoji) then |
|||
client:removeListener("reactionAdd",grabEmoji) |
|||
msg:reply("Couldn't add reaction - emoji might be invalid") |
|||
end |
|||
end |
|||
}, |
|||
["button"] = { |
|||
help = { |
|||
title = "Add a button that runs specific command when pressed", |
|||
description = "Note: you cannot assign more than one action to a single reaction \n``$user`` gets replaced with the id of the user that interacted with the reaction.", |
|||
fields = { |
|||
{name = "Usage: ",value = "button <emoji> <command>"}, |
|||
{name = "Perms: ",value = "administrator"} |
|||
} |
|||
}, |
|||
args = { |
|||
"string", |
|||
"string", |
|||
}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if not segment.pivot then |
|||
msg:reply("Pivot not selected. Use "..globals.prefix.."pivot to select it and then try again") |
|||
return nil |
|||
end |
|||
local emoji = getEmoji(args[1]) |
|||
local channel = guild:getChannel(segment.pivot.channel) |
|||
if not channel then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local message = channel:getMessage(segment.pivot.message) |
|||
if not message then |
|||
msg:reply("Something went horribly wrong, but it's not your fault. This incident has been (hopefully) reported") |
|||
return nil |
|||
end |
|||
local grabEmoji = function(reaction) |
|||
segment.pivot.buttons[tostring(reaction.emojiId or reaction.emojiName)] = { |
|||
type = "button", |
|||
on = args[2], |
|||
} |
|||
msg:reply("Button added successfully") |
|||
end |
|||
message:removeReaction(emoji,client.user.id) |
|||
client:once("reactionAdd",grabEmoji) |
|||
if not message:addReaction(emoji) then |
|||
client:removeListener("reactionAdd",grabEmoji) |
|||
msg:reply("Couldn't add reaction - emoji might be invalid") |
|||
end |
|||
end |
|||
}, |
|||
} |
|||
|
|||
|
|||
local buttonOn = function(message,hash,userID) |
|||
if not message then |
|||
log("ERROR","Attempted to find a deleted message") |
|||
return |
|||
end |
|||
if segment.pivots[tostring(message.id)] and userID ~= client.user.id then |
|||
local current_pivot = segment.pivots[tostring(message.id)] |
|||
if current_pivot.buttons[tostring(hash)] then |
|||
local current_button = current_pivot.buttons[tostring(hash)] |
|||
local new_content |
|||
if current_button.on then |
|||
new_content = current_button.on:gsub("%$user",userID) |
|||
end |
|||
if current_button.type == "role-toggler" then |
|||
guild:getMember(userID):addRole(current_button.role) |
|||
end |
|||
if current_button.type == "toggler" then |
|||
emulate.send(message,{ |
|||
delete = function() end, |
|||
content = new_content |
|||
}) |
|||
end |
|||
if current_button.type == "button" then |
|||
emulate.send(message,{ |
|||
delete = function() end, |
|||
content = new_content |
|||
}) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
local buttonOff = function(message,hash,userID) |
|||
if not message then |
|||
log("ERROR","Attempted to find a deleted message") |
|||
return |
|||
end |
|||
if segment.pivots[tostring(message.id)] and userID ~= client.user.id then |
|||
local current_pivot = segment.pivots[tostring(message.id)] |
|||
if current_pivot.buttons[tostring(hash)] then |
|||
local current_button = current_pivot.buttons[tostring(hash)] |
|||
local new_content |
|||
if current_button.off then |
|||
new_content = current_button.off:gsub("%$user",userID) |
|||
end |
|||
if current_button.type == "role-toggler" then |
|||
guild:getMember(userID):removeRole(current_button.role) |
|||
end |
|||
if current_button.type == "toggler" then |
|||
emulate.send(message,{ |
|||
delete = function() end, |
|||
content = new_content |
|||
}) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
events:on("reactionAdd",function(reaction,userID) |
|||
local message = reaction.message |
|||
local hash = tostring(reaction.emojiId or reaction.emojiName) |
|||
buttonOn(message,hash,userID) |
|||
end) |
|||
|
|||
events:on("reactionRemove",function(reaction,userID) |
|||
local message = reaction.message |
|||
local hash = tostring(reaction.emojiId or reaction.emojiName) |
|||
buttonOff(message,hash,userID) |
|||
end) |
|||
|
|||
events:on("reactionAddUncached",function(channelId,messageId,hash,userId) |
|||
local message = client:getChannel(channelId):getMessage(messageId) |
|||
local hash = tostring(hash) |
|||
buttonOn(message,hash,userId) |
|||
end) |
|||
|
|||
events:on("reactionRemoveUncached",function(channelId,messageId,hash,userId) |
|||
local message = client:getChannel(channelId):getMessage(messageId) |
|||
local hash = tostring(hash) |
|||
buttonOff(message,hash,userId) |
|||
end) |
|||
|
|||
events:on("serverSaveConfig",function() |
|||
file.writeJSON("./servers/"..id.."/reactions.json",segment.pivots) |
|||
end) |
|||
|
|||
return segment |
@ -1,120 +0,0 @@ |
|||
segment = {} |
|||
local check_perms = require("check_perms") |
|||
local fake_server = { |
|||
id = id |
|||
} |
|||
local file = require("file") |
|||
file.activate_json(require("json")) |
|||
local overlay = file.readJSON("./servers/"..id.."/overlay.json",{}) |
|||
local cached_commands = {} |
|||
events:on("commandPoolUpdate",function() |
|||
local commands = plugins.get()["commands"] |
|||
for k,v in pairs(commands) do |
|||
if not cached_commands[k] then |
|||
if overlay[k] then |
|||
if not v.perms then |
|||
v.perms = {} |
|||
end |
|||
v.perms.users = overlay[k].users or v.perms.users |
|||
v.perms.roles = overlay[k].roles or v.perms.roles |
|||
end |
|||
cached_commands[k] = true |
|||
end |
|||
end |
|||
for k,v in pairs(cached_commands) do |
|||
if not commands[k] then |
|||
cached_commands[k] = nil |
|||
end |
|||
end |
|||
end) |
|||
|
|||
events:on("serverSaveConfig",function() |
|||
file.writeJSON("./servers/"..id.."/overlay.json",overlay) |
|||
end) |
|||
|
|||
segment.commands = { |
|||
["rules"] = { |
|||
args = { |
|||
"string", |
|||
"string", |
|||
}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
} |
|||
exec = function(msg,args,opts) |
|||
local target,command = args[1],args[2] |
|||
local commands = plugins.get()["commands"] |
|||
if not commands[target] then |
|||
msg:reply("Target command not found") |
|||
return |
|||
end |
|||
local name = target |
|||
target = commands[target] |
|||
if command == "list" then |
|||
local roles = "```" |
|||
for k,v in pairs(target.perms.roles or {}) do |
|||
roles = roles..((v > 0 and "allow ") or (v < 0 and "disallow "))..k.."\n" |
|||
end |
|||
roles = roles.." ```" |
|||
local users = "```" |
|||
for k,v in pairs(target.perms.users or {}) do |
|||
users = users..((v > 0 and "allow ") or (v < 0 and "disallow "))..k.."\n" |
|||
end |
|||
users = users.." ```" |
|||
msg:reply({embed={ |
|||
title = "Custom permissions for command ``"..name.."``", |
|||
fields = { |
|||
{name = "Roles",value = roles}, |
|||
{name = "Users",value = users} |
|||
} |
|||
}}) |
|||
else |
|||
if not check_perms(fake_server,target,msg,require("discordia")) then |
|||
msg:reply("You don't have a high enough permission to change rules for this command") |
|||
return |
|||
end |
|||
local type,id = args[3],args[4] |
|||
if not id then |
|||
msg:reply("Type and ID are needed to create a proper rule") |
|||
end |
|||
if (type ~= "user") and (type ~= "role") then |
|||
msg:reply("Type can only be ``user`` or ``role``") |
|||
end |
|||
id = id:match("%d+") |
|||
local state = 0 |
|||
if command == "allow" then |
|||
state = 1 |
|||
elseif command == "disallow" then |
|||
state = -1 |
|||
elseif command == "reset" then |
|||
state = nil |
|||
end |
|||
if not overlay[name] then |
|||
overlay[name] = {} |
|||
overlay[name].users = {} |
|||
overlay[name].roles = {} |
|||
end |
|||
if not target.perms then |
|||
target.perms = {} |
|||
end |
|||
if type == "user" then |
|||
if not target.perms.users then |
|||
target.perms.users = {} |
|||
end |
|||
target.perms.users[id] = state |
|||
overlay[name].users[id] = state |
|||
elseif type == "role" then |
|||
if not target.perms.roles then |
|||
target.perms.roles = {} |
|||
end |
|||
target.perms.roles[id] = state |
|||
overlay[name].roles[id] = state |
|||
end |
|||
msg:reply("Changes applied.") |
|||
end |
|||
end |
|||
} |
|||
} |
|||
return segment |
@ -1,362 +0,0 @@ |
|||
--haha yes time to make cron in lua |
|||
local segment = {} |
|||
segment.help = "Add tasks to be executed later" |
|||
local file = require("file") |
|||
file.activate_json(require("json")) |
|||
local utils = require("bot_utils") |
|||
local emulate = require("emulate")({ |
|||
client = client, |
|||
discordia = discordia |
|||
}) |
|||
segment.name = "task" |
|||
local preload_tab = file.readJSON("./servers/"..id.."/crontab.json",{}) |
|||
segment.tab = {} |
|||
globals.utc = globals.utc or 0 |
|||
globals.utc_minutes = globals.utc_minutes or 0 |
|||
segment.coroutines = {} |
|||
local absolute_fake_generator = require("absolute_fake") |
|||
local function cronTime(time) |
|||
if type(time) ~= "string" then |
|||
return false |
|||
end |
|||
local mask = {60,24,32,13} |
|||
local tokens = {} |
|||
local err = false |
|||
time:gsub("[%d%*]+",function(c) table.insert(tokens,c) end,4) |
|||
for I = 1,4 do --check if date/time format matches |
|||
if not ((tokens[I]:match("%d+") and tonumber(tokens[I]) < mask[I]) or ((tokens[I] == "*") and (I > 1))) then |
|||
err = true |
|||
end |
|||
end |
|||
if not err then |
|||
return tokens |
|||
else |
|||
return nil |
|||
end |
|||
end |
|||
|
|||
local function getFakeMessageOf(channel,member,content) |
|||
return absolute_fake_generator(client,discordia,member,channel,id,content) |
|||
end |
|||
|
|||
local function addEventTask(task) |
|||
if task.event and task.channel and task.member then |
|||
task.coroutineID = math.random(1000000000,9999999999) |
|||
while segment.coroutines[task.coroutineID] do |
|||
task.coroutineID = math.random(1000000000,9999999999) |
|||
end |
|||
local taskID = #segment.tab+1 |
|||
segment.coroutines[task.coroutineID] = function(check,args) |
|||
local check_func = ((type(check) == "function") and check) or (function() return true end) |
|||
if (not task.args) or (type(task.args) == "table" and check_func(task.args)) then |
|||
local content = task.task |
|||
for k,v in pairs(args or {}) do |
|||
content = content:gsub("%$"..k,tostring(v)) |
|||
end |
|||
local dupeable = getFakeMessageOf(task.channel,task.member) |
|||
if not dupeable then |
|||
log("ERROR","Failed to dupe a message properly") |
|||
return nil |
|||
end |
|||
emulate.send(dupeable,{ |
|||
content = content, |
|||
delete = function() end |
|||
}) |
|||
if task.once then |
|||
signals:removeListener(task.event,segment.coroutines[task.coroutineID]) |
|||
table.remove(segment.tab,taskID) |
|||
segment.coroutines[task.coroutineID] = nil |
|||
end |
|||
end |
|||
end |
|||
signals:on(task.event,segment.coroutines[task.coroutineID]) |
|||
table.insert(segment.tab,task) |
|||
return true |
|||
else |
|||
return false |
|||
end |
|||
end |
|||
|
|||
local function addTimeTask(task) |
|||
if type(task.time) == "table" then |
|||
table.insert(segment.tab,task) |
|||
return true |
|||
else |
|||
return false |
|||
end |
|||
end |
|||
|
|||
for k,v in pairs(preload_tab) do |
|||
if v.type == "event" then |
|||
addEventTask(v) |
|||
else |
|||
addTimeTask(v) |
|||
end |
|||
end |
|||
|
|||
segment.commands = { |
|||
["task"] = { |
|||
help = {embed = { |
|||
title = "Add tasks", |
|||
description = "Tasks are like cron tasks, in a sense that you specify when to execute them and what command to execute", |
|||
fields = { |
|||
{name = "Usage: ",value = "task (\"minute hour day month\" or @<event name> \"argument1\" \"argument2\") \"command\""}, |
|||
{name = "Perms: ",value = "Administrator"}, |
|||
{name = "Opts: ",value = [[ |
|||
--description=\"description here\" - self-descriptive |
|||
--once - remove the task after completion |
|||
]]}, |
|||
{name = "Examples: ",value = [[ |
|||
``task "5 10 * *" "]]..globals.prefix..[[speak hi"`` -- sends "hi" to the current channel at 10:05 every day every month |
|||
``task "5 10 15 *" "]]..globals.prefix..[[speak hi"`` -- sends "hi" to the current channel at 10:05 every 15th day of the month |
|||
``task --once "5 10 15 *" "]]..globals.prefix..[[speak hi"`` -- same as before, except the task gets removed after sending the message |
|||
additional examples can be found at https://github.com/yessiest/SuppaBot/wiki/Tasks |
|||
]]} |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
args = { |
|||
"string", |
|||
"string" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
local command = args[#args] |
|||
if args[1]:match("^@%w+") then |
|||
local event = args[1]:match("^@(%w+)") |
|||
local conditions = utils.slice(args,2,#args-1) |
|||
local status = addEventTask({ |
|||
type = "event", |
|||
channel = tostring(msg.channel.id), |
|||
member = tostring(msg.member.id), |
|||
event = event, |
|||
args = conditions, |
|||
task = command, |
|||
description = opts["description"] or "", |
|||
once = opts["once"] |
|||
}) |
|||
if status then |
|||
msg:reply("Task "..(#segment.tab).." added") |
|||
else |
|||
msg:reply("Failed to add task") |
|||
end |
|||
elseif args[1]:match("^ ?%d+ [%d*]+ [%d*]+ [%d*]+ ?$") then |
|||
local status = addTimeTask({ |
|||
type = "time", |
|||
time = cronTime(args[1]:match("^ ?%d+ [%d*]+ [%d*]+ [%d*]+ ?$")), |
|||
channel = tostring(msg.channel.id), |
|||
member = tostring(msg.member.id), |
|||
task = command, |
|||
description = opts["description"] or "", |
|||
once = opts["once"] |
|||
}) |
|||
if status then |
|||
msg:reply("Task "..(#segment.tab).." added") |
|||
else |
|||
msg:reply("Failed to add task") |
|||
end |
|||
else |
|||
msg:reply("Syntax error") |
|||
end |
|||
end |
|||
}, |
|||
["tasks"] = { |
|||
help = {embed = { |
|||
title = "List all tasks", |
|||
description = "Bold white text is conditions for the task, code block is the command to be executed", |
|||
fields = { |
|||
{name = "Usage: ",value = "tasks"}, |
|||
{name = "Perms: ",value = "Administrator"}, |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
msg:reply({embed = { |
|||
title = "Tasks: ", |
|||
fields = (function() |
|||
local output = {} |
|||
for k,v in pairs(segment.tab) do |
|||
if v.type == "event" then |
|||
table.insert(output,{ |
|||
name = tostring(k)..": @"..v.event.." "..table.concat(v.args," "), |
|||
value = "```"..v.task.."```\n"..tostring(v.description), |
|||
inline = true |
|||
}) |
|||
elseif v.type == "time" then |
|||
table.insert(output,{ |
|||
name = tostring(k)..": "..table.concat(v.time," "), |
|||
value = "```"..v.task.."```\n"..tostring(v.description), |
|||
inline = true |
|||
}) |
|||
end |
|||
end |
|||
return output |
|||
end)() |
|||
}}) |
|||
end |
|||
}, |
|||
["task-remove"] = { |
|||
help = {embed = { |
|||
title = "Remove a task", |
|||
description = "That one is self-descriptive", |
|||
fields = { |
|||
{name = "Usage: ",value = "remove-task <task id>"}, |
|||
{name = "Perms: ",value = "Administrator"}, |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
args = { |
|||
"number" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if segment.tab[args[1]] then |
|||
local task = segment.tab[args[1]] |
|||
if task.type == "event" then |
|||
signals:removeListener(task.event,segment.coroutines[task.coroutineID]) |
|||
segment.coroutines[task.coroutineID] = nil |
|||
end |
|||
table.remove(segment.tab,args[2]) |
|||
msg:reply("Task "..args[1].." removed") |
|||
else |
|||
msg:reply("Task "..args[1].." not found") |
|||
end |
|||
end |
|||
}, |
|||
["utc"] = { |
|||
help = {embed = { |
|||
title = "Set the UTC time offset", |
|||
description = "If your UTC time offset is x:45 or x:30 simply add \":30\" or \"45\" to the number accordingly", |
|||
fields = { |
|||
{name = "Usage: ",value = "utc <hour>[:<minute>]"}, |
|||
{name = "Perms: ",value = "Administrator"}, |
|||
} |
|||
}}, |
|||
perms = { |
|||
perms = { |
|||
"administrator" |
|||
} |
|||
}, |
|||
args = { |
|||
"string" |
|||
}, |
|||
exec = function(msg,args,opts) |
|||
if args[1]:match("^%d+$") then |
|||
globals.utc = tonumber(args[1]:match("^(%d+)$")) |
|||
msg:reply("UTC offset set") |
|||
elseif args[1]:match("^%d+:%d+$") then |
|||
globals.utc = tonumber(args[1]:match("^(%d+):%d+$")) |
|||
globals.utc_minutes = tonumber(args[1]:match("^%d+:(%d+)$")) |
|||
msg:reply("UTC offset set") |
|||
else |
|||
msg:reply("Invalid syntax") |
|||
end |
|||
end |
|||
}, |
|||
["time"] = { |
|||
help = {embed = { |
|||
title = "View the internal bot time", |
|||
description = "If you've set a time offset previously, it will get accounted", |
|||
fields = { |
|||
{name = "Usage: ",value = "time"}, |
|||
{name = "Perms: ",value = "all"}, |
|||
} |
|||
}}, |
|||
exec = function(msg,args,opts) |
|||
local utc_time = os.date("%c",os.time()+(3600)*(globals.utc-4)+(60)*(globals.utc_minutes)) |
|||
msg:reply(utc_time) |
|||
end |
|||
} |
|||
} |
|||
|
|||
segment.unload = function() |
|||
for k,v in pairs(segment.tab) do |
|||
if v.type == "event" then |
|||
signals:removeListener(v.event,segment.coroutines[v.coroutineID]) |
|||
segment.coroutines[v.coroutineID] = nil |
|||
segment.tab[k] = nil |
|||
end |
|||
end |
|||
end |
|||
|
|||
local function check_time(date,crondate) |
|||
local mask = {"min","hour","day","month"} |
|||
local output = true |
|||
for I = 1,4 do |
|||
if not (tonumber(crondate[I]) == tonumber(date[mask[I]]) or crondate[I] == "*") then |
|||
output = false |
|||
end |
|||
end |
|||
return output |
|||
end |
|||
|
|||
events:on("messageCreate",function(msg) |
|||
signals:emit("message",function(args) |
|||
local output = true |
|||
if not args[1] then |
|||
output = true |
|||
elseif msg.content:find(args[1],1,true) then |
|||
output = true |
|||
else |
|||
output = false |
|||
end |
|||
if output and (tostring(msg.author.id) == tostring(client.user.id)) then |
|||
output = false |
|||
end |
|||
if output and (msg.emulated) then |
|||
output = false |
|||
end |
|||
if output and (not args[2]) then |
|||
output = true |
|||
elseif output and (msg.author.name:find(args[2],1,true)) then |
|||
output = true |
|||
else |
|||
output = false |
|||
end |
|||
return output |
|||
end,{ |
|||
user = msg.author.id, |
|||
content = msg.content, |
|||
name = msg.author.name, |
|||
ctxid = msg.id |
|||
}) |
|||
return |
|||
end) |
|||
|
|||
events:on("serverSaveConfig",function() |
|||
file.writeJSON("./servers/"..id.."/crontab.json",segment.tab) |
|||
end) |
|||
|
|||
events:on("clock",function() |
|||
if tonumber(os.time())%60 == 30 then |
|||
local utc_time = os.date("*t",os.time()+(3600)*(globals.utc-4)+(60)*(globals.utc_minutes)) |
|||
for k,v in pairs(segment.tab) do |
|||
if (v.type == "time") and check_time(utc_time,v.time) then |
|||
emulate_message = getFakeMessageOf(v.channel,v.member) |
|||
if emulate_message then |
|||
emulate.send(emulate_message,{ |
|||
content = v.task, |
|||
delete = function() end |
|||
}) |
|||
else |
|||
log("ERROR","There are no messages to dupe a new one from") |
|||
end |
|||
if v.once then |
|||
table.remove(segment.tab,k) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end) |
|||
|
|||
return segment |
Write
Preview
Loading…
Cancel
Save
Reference in new issue