diff --git a/README.md b/README.md index b61e7af..5c7ec4e 100755 --- a/README.md +++ b/README.md @@ -53,13 +53,13 @@ Most plugins are intended for public use, but a few are for other purposes, like A plugin can have five components, and two of them are required: -| Component | Description | Required? | -|:----------|:---------------------------------------------|:----------| -| action | Main function. Expects `msg` table as an argument. | Y | -| triggers | Table of triggers for the plugin. Uses Lua patterns. | Y | -| cron | Optional function to be called every minute. | N | -| command | Basic command and syntax. Listed in the help text. | N | -| doc | Usage for the plugin. Returned by "/help $command". | N | +| Component | Description | Required? | +|:----------|:-----------------------------------------------------|:----------| +| action | Main function. Expects `msg` table as an argument. | Y | +| triggers | Table of triggers for the plugin. Uses Lua patterns. | Y | +| cron | Optional function to be called every minute. | N | +| command | Basic command and syntax. Listed in the help text. | N | +| doc | Usage for the plugin. Returned by "/help $command". | N | The `on_msg_receive()` function adds a few variables to the `msg` table for your convenience. These are self-explanatory: `msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`. diff --git a/bindings.lua b/bindings.lua index 0ddf9b5..db117bd 100755 --- a/bindings.lua +++ b/bindings.lua @@ -2,17 +2,13 @@ -- Bindings for the Telegram bot API. -- https://core.telegram.org/bots/api -assert(HTTPS) -assert(JSON) -assert(URL) +local bindings = {} -local BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key +local HTTPS = require('ssl.https') +local JSON = require('cjson') +local URL = require('socket.url') -if config.bot_api_key == '' then - error('You did not set your bot token in config.lua!') -end - -sendRequest = function(url) +function bindings.sendRequest(url) local dat, res = HTTPS.request(url) @@ -30,28 +26,28 @@ sendRequest = function(url) end -getMe = function() +function bindings:getMe() - local url = BASE_URL .. '/getMe' - return sendRequest(url) + local url = self.BASE_URL .. '/getMe' + return bindings.sendRequest(url) end -getUpdates = function(offset) +function bindings:getUpdates(offset) - local url = BASE_URL .. '/getUpdates?timeout=20' + local url = self.BASE_URL .. '/getUpdates?timeout=20' if offset then url = url .. '&offset=' .. offset end - return sendRequest(url) + return bindings.sendRequest(url) end -sendMessage = function(chat_id, text, disable_web_page_preview, reply_to_message_id, use_markdown, disable_notification) +function bindings:sendMessage(chat_id, text, disable_web_page_preview, reply_to_message_id, use_markdown, disable_notification) - local url = BASE_URL .. '/sendMessage?chat_id=' .. chat_id .. '&text=' .. URL.escape(text) + local url = self.BASE_URL .. '/sendMessage?chat_id=' .. chat_id .. '&text=' .. URL.escape(text) if disable_web_page_preview == true then url = url .. '&disable_web_page_preview=true' @@ -69,30 +65,30 @@ sendMessage = function(chat_id, text, disable_web_page_preview, reply_to_message url = url .. '&disable_notification=true' end - return sendRequest(url) + return bindings.sendRequest(url) end -sendReply = function(msg, text) +function bindings:sendReply(msg, text) - return sendMessage(msg.chat.id, text, true, msg.message_id) + return bindings.sendMessage(self, msg.chat.id, text, true, msg.message_id) end -sendChatAction = function(chat_id, action) +function bindings:sendChatAction(chat_id, action) -- Support actions are typing, upload_photo, record_video, upload_video, record_audio, upload_audio, upload_document, find_location - local url = BASE_URL .. '/sendChatAction?chat_id=' .. chat_id .. '&action=' .. action - return sendRequest(url) + local url = self.BASE_URL .. '/sendChatAction?chat_id=' .. chat_id .. '&action=' .. action + return bindings.sendRequest(self, url) end -sendLocation = function(chat_id, latitude, longitude, reply_to_message_id, disable_notification) +function bindings:sendLocation(chat_id, latitude, longitude, reply_to_message_id, disable_notification) if latitude == 0 then latitude = 0.001 end if longitude == 0 then longitude = 0.001 end - local url = BASE_URL .. '/sendLocation?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude + local url = self.BASE_URL .. '/sendLocation?chat_id=' .. chat_id .. '&latitude=' .. latitude .. '&longitude=' .. longitude if reply_to_message_id then url = url .. '&reply_to_message_id=' .. reply_to_message_id @@ -102,27 +98,27 @@ sendLocation = function(chat_id, latitude, longitude, reply_to_message_id, disab url = url .. '&disable_notification=true' end - return sendRequest(url) + return bindings.sendRequest(self, url) end -forwardMessage = function(chat_id, from_chat_id, message_id, disable_notification) +function bindings:forwardMessage(chat_id, from_chat_id, message_id, disable_notification) - local url = BASE_URL .. '/forwardMessage?chat_id=' .. chat_id .. '&from_chat_id=' .. from_chat_id .. '&message_id=' .. message_id + local url = self.BASE_URL .. '/forwardMessage?chat_id=' .. chat_id .. '&from_chat_id=' .. from_chat_id .. '&message_id=' .. message_id if disable_notification then url = url .. '&disable_notification=true' end - return sendRequest(url) + return bindings.sendRequest(self, url) end -- TODO: More of this. -sendPhotoID = function(chat_id, file_id, caption, reply_to_message_id, disable_notification) +function bindings:sendPhotoID(chat_id, file_id, caption, reply_to_message_id, disable_notification) - local url = BASE_URL .. '/sendPhoto?chat_id=' .. chat_id .. '&photo=' .. file_id + local url = self.BASE_URL .. '/sendPhoto?chat_id=' .. chat_id .. '&photo=' .. file_id if caption then url = url .. '&caption=' .. URL.escape(caption) @@ -136,20 +132,20 @@ sendPhotoID = function(chat_id, file_id, caption, reply_to_message_id, disable_n url = url .. '&disable_notification=true' end - return sendRequest(url) + return bindings.sendRequest(self, url) end -curlRequest = function(curl_command) +function bindings.curlRequest(curl_command) -- Use at your own risk. Will not check for success. io.popen(curl_command) end -sendPhoto = function(chat_id, photo, caption, reply_to_message_id, disable_notification) +function bindings:sendPhoto(chat_id, photo, caption, reply_to_message_id, disable_notification) - local url = BASE_URL .. '/sendPhoto' + local url = self.BASE_URL .. '/sendPhoto' local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "photo=@' .. photo .. '"' @@ -165,13 +161,13 @@ sendPhoto = function(chat_id, photo, caption, reply_to_message_id, disable_notif curl_command = curl_command .. ' -F "disable_notification=true"' end - return curlRequest(curl_command) + return bindings.curlRequest(curl_command) end -sendDocument = function(chat_id, document, reply_to_message_id, disable_notification) +function bindings:sendDocument(chat_id, document, reply_to_message_id, disable_notification) - local url = BASE_URL .. '/sendDocument' + local url = self.BASE_URL .. '/sendDocument' local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "document=@' .. document .. '"' @@ -183,13 +179,13 @@ sendDocument = function(chat_id, document, reply_to_message_id, disable_notifica curl_command = curl_command .. ' -F "disable_notification=true"' end - return curlRequest(curl_command) + return bindings.curlRequest(curl_command) end -sendSticker = function(chat_id, sticker, reply_to_message_id, disable_notification) +function bindings:sendSticker(chat_id, sticker, reply_to_message_id, disable_notification) - local url = BASE_URL .. '/sendSticker' + local url = self.BASE_URL .. '/sendSticker' local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "sticker=@' .. sticker .. '"' @@ -201,13 +197,13 @@ sendSticker = function(chat_id, sticker, reply_to_message_id, disable_notificati curl_command = curl_command .. ' -F "disable_notification=true"' end - return curlRequest(curl_command) + return bindings.curlRequest(curl_command) end -sendAudio = function(chat_id, audio, reply_to_message_id, duration, performer, title, disable_notification) +function bindings:sendAudio(chat_id, audio, reply_to_message_id, duration, performer, title, disable_notification) - local url = BASE_URL .. '/sendAudio' + local url = self.BASE_URL .. '/sendAudio' local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "audio=@' .. audio .. '"' @@ -231,13 +227,13 @@ sendAudio = function(chat_id, audio, reply_to_message_id, duration, performer, t curl_command = curl_command .. ' -F "disable_notification=true"' end - return curlRequest(curl_command) + return bindings.curlRequest(curl_command) end -sendVideo = function(chat_id, video, reply_to_message_id, duration, caption, disable_notification) +function bindings:sendVideo(chat_id, video, reply_to_message_id, duration, caption, disable_notification) - local url = BASE_URL .. '/sendVideo' + local url = self.BASE_URL .. '/sendVideo' local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "video=@' .. video .. '"' @@ -257,13 +253,13 @@ sendVideo = function(chat_id, video, reply_to_message_id, duration, caption, dis curl_command = curl_command .. ' -F "disable_notification=true"' end - return curlRequest(curl_command) + return bindings.curlRequest(curl_command) end -sendVoice = function(chat_id, voice, reply_to_message_id, duration, disable_notification) +function bindings:sendVoice(chat_id, voice, reply_to_message_id, duration, disable_notification) - local url = BASE_URL .. '/sendVoice' + local url = self.BASE_URL .. '/sendVoice' local curl_command = 'curl -s "' .. url .. '" -F "chat_id=' .. chat_id .. '" -F "voice=@' .. voice .. '"' @@ -279,6 +275,8 @@ sendVoice = function(chat_id, voice, reply_to_message_id, duration, disable_noti curl_command = curl_command .. ' -F "disable_notification=true"' end - return curlRequest(curl_command) + return bindings.curlRequest(curl_command) end + +return bindings diff --git a/bot.lua b/bot.lua index cc8e331..915d8f7 100755 --- a/bot.lua +++ b/bot.lua @@ -1,73 +1,77 @@ -HTTP = require('socket.http') -HTTPS = require('ssl.https') -URL = require('socket.url') -JSON = require('cjson') +local bot = {} -version = '3.5' +local bindings = require('bindings') -- Load Telegram bindings. +local utilities = require('utilities') -- Load miscellaneous and cross-plugin functions. -bot_init = function() -- The function run when the bot is started or reloaded. +bot.version = '3.5' - config = dofile('config.lua') -- Load configuration file. - dofile('bindings.lua') -- Load Telegram bindings. - dofile('utilities.lua') -- Load miscellaneous and cross-plugin functions. +function bot:init() -- The function run when the bot is started or reloaded. + + self.config = require('config') -- Load configuration file. + + self.BASE_URL = 'https://api.telegram.org/bot' .. self.config.bot_api_key + if self.config.bot_api_key == '' then + error('You did not set your bot token in config.lua!') + end -- Fetch bot information. Try until it succeeds. - repeat bot = getMe() until bot - bot = bot.result + repeat self.info = bindings.getMe(self) until self.info + self.info = self.info.result -- Load the "database"! ;) - if not database then - database = load_data(bot.username..'.db') + if not self.database then + self.database = utilities.load_data(self.info.username..'.db') end - plugins = {} -- Load plugins. - for i,v in ipairs(config.plugins) do - local p = dofile('plugins/'..v) - table.insert(plugins, p) + self.plugins = {} -- Load plugins. + for _,v in ipairs(self.config.plugins) do + local p = require('plugins/'..v) + table.insert(self.plugins, p) + if p.init then p.init(self) end end - print('@' .. bot.username .. ', AKA ' .. bot.first_name ..' ('..bot.id..')') + print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')') -- Generate a random seed and "pop" the first random number. :) math.randomseed(os.time()) math.random() - last_update = last_update or 0 -- Set loop variables: Update offset, - last_cron = last_cron or os.date('%M') -- the time of the last cron job, - is_started = true -- and whether or not the bot should be running. - database.users = database.users or {} -- Table to cache userdata. - database.users[tostring(bot.id)] = bot + self.last_update = self.last_update or 0 -- Set loop variables: Update offset, + self.last_cron = self.last_cron or os.date('%M') -- the time of the last cron job, + self.is_started = true -- and whether or not the bot should be running. + self.database.users = self.database.users or {} -- Table to cache userdata. + self.database.users[tostring(self.info.id)] = self.info -- Migration code. Remove in 3.6. - if database.lastfm then - for k,v in pairs(database.lastfm) do - if not database.users[k] then database.users[k] = {} end - database.users[k].lastfm = v + if self.database.lastfm then + for k,v in pairs(self.database.lastfm) do + if not self.database.users[k] then self.database.users[k] = {} end + self.database.users[k].lastfm = v end end -- Migration code. Remove in 3.6. - if database.nicknames then - for k,v in pairs(database.nicknames) do - if not database.users[k] then database.users[k] = {} end - database.users[k].nickname = v + if self.database.nicknames then + for k,v in pairs(self.database.nicknames) do + if not self.database.users[k] then self.database.users[k] = {} end + self.database.users[k].nickname = v end end end -on_msg_receive = function(msg) -- The fn run whenever a message is received. +function bot:on_msg_receive(msg) -- The fn run whenever a message is received. -- Create a user entry if it does not exist. - if not database.users[tostring(msg.from.id)] then - database.users[tostring(msg.from.id)] = {} + if not self.database.users[tostring(msg.from.id)] then + self.database.users[tostring(msg.from.id)] = {} end -- Clear things that no longer exist. - database.users[tostring(msg.from.id)].username = nil - database.users[tostring(msg.from.id)].last_name = nil + self.database.users[tostring(msg.from.id)].username = nil + self.database.users[tostring(msg.from.id)].last_name = nil -- Wee. for k,v in pairs(msg.from) do - database.users[tostring(msg.from.id)][k] = v + self.database.users[tostring(msg.from.id)][k] = v end if msg.date < os.time() - 5 then return end -- Do not process old messages. @@ -78,24 +82,24 @@ on_msg_receive = function(msg) -- The fn run whenever a message is received. end -- If the replied-to message has a caption, make that its text. if msg.text:match('^/start .+') then - msg.text = '/' .. msg.text:input() + msg.text = '/' .. utilities.input(msg.text) end - for i,v in ipairs(plugins) do - for k,w in pairs(v.triggers) do + for _,v in ipairs(self.plugins) do + for _,w in pairs(v.triggers) do if string.match(msg.text:lower(), w) then -- a few shortcuts msg.chat.id_str = tostring(msg.chat.id) msg.from.id_str = tostring(msg.from.id) msg.text_lower = msg.text:lower() - msg.from.name = build_name(msg.from.first_name, msg.from.last_name) + msg.from.name = utilities.build_name(msg.from.first_name, msg.from.last_name) local success, result = pcall(function() - return v.action(msg) + return v.action(self, msg) end) if not success then - sendReply(msg, 'Sorry, an unexpected error occurred.') - handle_exception(result, msg.from.id .. ': ' .. msg.text) + bindings.sendReply(self, msg, 'Sorry, an unexpected error occurred.') + bindings.handle_exception(self, result, msg.from.id .. ': ' .. msg.text) return end -- If the action returns a table, make that table msg. @@ -111,28 +115,30 @@ on_msg_receive = function(msg) -- The fn run whenever a message is received. end -bot_init() -- Actually start the script. Run the bot_init function. +bot.init(bot) -- Actually start the script. Run the bot_init function. -while is_started do -- Start a loop while the bot should be running. +while bot.is_started do -- Start a loop while the bot should be running. - local res = getUpdates(last_update+1) -- Get the latest updates! - if res then - for i,v in ipairs(res.result) do -- Go through every new message. - last_update = v.update_id - on_msg_receive(v.message) + do + local res = bindings.getUpdates(bot, bot.last_update+1) -- Get the latest updates! + if res then + for _,v in ipairs(res.result) do -- Go through every new message. + bot.last_update = v.update_id + bot.on_msg_receive(bot, v.message) + end + else + print(bot.config.errors.connection) end - else - print(config.errors.connection) end - if last_cron ~= os.date('%M') then -- Run cron jobs every minute. - last_cron = os.date('%M') - save_data(bot.username..'.db', database) -- Save the database. - for i,v in ipairs(plugins) do + if bot.last_cron ~= os.date('%M') then -- Run cron jobs every minute. + bot.last_cron = os.date('%M') + utilities.save_data(bot.info.username..'.db', bot.database) -- Save the database. + for i,v in ipairs(bot.plugins) do if v.cron then -- Call each plugin's cron function, if it has one. local res, err = pcall(function() v.cron() end) if not res then - handle_exception(err, 'CRON: ' .. i) + utilities.handle_exception(bot, err, 'CRON: ' .. i) end end end @@ -141,5 +147,5 @@ while is_started do -- Start a loop while the bot should be running. end -- Save the database before exiting. -save_data(bot.username..'.db', database) +utilities.save_data(bot.info.username..'.db', bot.database) print('Halted.') diff --git a/plugins/about.lua b/plugins/about.lua index f57dc28..f64ac50 100755 --- a/plugins/about.lua +++ b/plugins/about.lua @@ -1,26 +1,30 @@ -local command = 'about' -local doc = '`Returns information about the bot.`' +local about = {} -local triggers = { +local bindings = require('bindings') + +about.command = 'about' +about.doc = '`Returns information about the bot.`' + +about.triggers = { '' } -local action = function(msg) +function about:action(msg) -- Filthy hack, but here is where we'll stop forwarded messages from hitting -- other plugins. if msg.forward_from then return end - local message = config.about_text .. '\nBased on @otouto v'..version..' by topkecleon.' + local message = self.config.about_text .. '\nBased on @otouto v'..self.version..' by topkecleon.' - if msg.new_chat_participant and msg.new_chat_participant.id == bot.id then - sendMessage(msg.chat.id, message, true) + if msg.new_chat_participant and msg.new_chat_participant.id == self.info.id then + bindings.sendMessage(self, msg.chat.id, message, true) return - elseif msg.text_lower:match('^/about[@'..bot.username..']*') then - sendMessage(msg.chat.id, message, true) + elseif msg.text_lower:match('^/about[@'..self.info.username..']*') then + bindings.sendMessage(self, msg.chat.id, message, true) return elseif msg.text_lower:match('^/start') then - sendMessage(msg.chat.id, message, true) + bindings.sendMessage(self, msg.chat.id, message, true) return end @@ -28,9 +32,4 @@ local action = function(msg) end -return { - action = action, - triggers = triggers, - doc = doc, - command = command -} +return about diff --git a/plugins/administration.lua b/plugins/administration.lua index a92bf9e..3d56316 100644 --- a/plugins/administration.lua +++ b/plugins/administration.lua @@ -25,45 +25,56 @@ ]]-- - -- Build the administration db if nonexistent. -if not database.administration then - database.administration = { - admins = {}, - groups = {}, - activity = {} - } -end +local JSON = require('cjson') +local drua = dofile('drua-tg/drua-tg.lua') +local bindings = require('bindings') +local utilities = require('utilities') -admin_temp = { - help = {}, - flood = {} -} +local administration = {} - -- Migration code: Remove this in v1.8. - -- Most recent group activity is now cached for group listings. -if not database.administration.activity then - database.administration.activity = {} - for k,v in pairs(database.administration.groups) do - table.insert(database.administration.activity, k) +function administration:init() + -- Build the administration db if nonexistent. + if not self.database.administration then + self.database.administration = { + admins = {}, + groups = {}, + activity = {} + } end -end - -- Migration code: Remove this in v1.9. - -- Groups have single governors now. -for k,v in pairs(database.administration.groups) do - if v.govs and table_size(v.govs) > 0 then - for key, val in pairs(v.govs) do - v.governor = key - break + self.admin_temp = { + help = {}, + flood = {} + } + + -- Migration code: Remove this in v1.8. + -- Most recent group activity is now cached for group listings. + if not self.database.administration.activity then + self.database.administration.activity = {} + for k,_ in pairs(self.database.administration.groups) do + table.insert(self.database.administration.activity, k) end end - v.govs = nil + + -- Migration code: Remove this in v1.9. + -- Groups have single governors now. + for _,group in pairs(self.database.administration.groups) do + if group.govs then + for gov, _ in pairs(group.govs) do + group.governor = gov + break + end + end + group.govs = nil + end + + drua.PORT = self.config.cli_port or 4567 + + administration.init_command(self) + end -drua = dofile('drua-tg/drua-tg.lua') -drua.PORT = config.cli_port or 4567 - -local flags = { +administration.flags = { [1] = { name = 'unlisted', desc = 'Removes this group from the group listing.', @@ -104,7 +115,7 @@ local flags = { } } -local antiflood = { +administration.antiflood = { text = 5, voice = 5, audio = 5, @@ -116,7 +127,7 @@ local antiflood = { sticker = 20 } -local ranks = { +administration.ranks = { [0] = 'Banned', [1] = 'Users', [2] = 'Moderators', @@ -125,32 +136,32 @@ local ranks = { [5] = 'Owner' } -local get_rank = function(target, chat) +function administration:get_rank(target, chat) target = tostring(target) if chat then chat = tostring(chat) end - if tonumber(target) == config.admin or tonumber(target) == bot.id then + if tonumber(target) == self.config.admin or tonumber(target) == self.info.id then return 5 end - if database.administration.admins[target] then + if self.database.administration.admins[target] then return 4 end - if chat and database.administration.groups[chat] then - if database.administration.groups[chat].governor == tonumber(target) then + if chat and self.database.administration.groups[chat] then + if self.database.administration.groups[chat].governor == tonumber(target) then return 3 - elseif database.administration.groups[chat].mods[target] then + elseif self.database.administration.groups[chat].mods[target] then return 2 - elseif database.administration.groups[chat].bans[target] then + elseif self.database.administration.groups[chat].bans[target] then return 0 end end - if database.blacklist[target] then + if self.database.blacklist[target] then return 0 end @@ -158,28 +169,28 @@ local get_rank = function(target, chat) end -local get_target = function(msg) +function administration:get_target(msg) - local target = user_from_message(msg) + local target = utilities.user_from_message(self, msg) if target.id then - target.rank = get_rank(target.id, msg.chat.id) + target.rank = administration.get_rank(self, target.id, msg.chat.id) end return target end -local mod_format = function(id) +function administration:mod_format(id) id = tostring(id) - local user = database.users[id] or { first_name = 'Unknown' } - local name = build_name(user.first_name, user.last_name) - name = markdown_escape(name) + local user = self.database.users[id] or { first_name = 'Unknown' } + local name = utilities.build_name(user.first_name, user.last_name) + name = utilities.markdown_escape(name) local output = '• ' .. name .. ' `[' .. id .. ']`\n' return output end -local get_desc = function(chat_id) +function administration:get_desc(chat_id) - local group = database.administration.groups[tostring(chat_id)] + local group = self.database.administration.groups[tostring(chat_id)] local t = {} if group.link then table.insert(t, '*Welcome to* [' .. group.name .. '](' .. group.link .. ')*!*') @@ -197,22 +208,22 @@ local get_desc = function(chat_id) table.insert(t, rulelist:trim()) end local flaglist = '' - for i = 1, #flags do + for i = 1, #administration.flags do if group.flags[i] then - flaglist = flaglist .. '• ' .. flags[i].short .. '\n' + flaglist = flaglist .. '• ' .. administration.flags[i].short .. '\n' end end if flaglist ~= '' then table.insert(t, '*Flags:*\n' .. flaglist:trim()) end if group.governor then - local gov = database.users[tostring(group.governor)] - local s = build_name(gov.first_name, gov.last_name):md_escape() .. ' `[' .. gov.id .. ']`' + local gov = self.database.users[tostring(group.governor)] + local s = utilities.md_escape(utilities.build_name(gov.first_name, gov.last_name)) .. ' `[' .. gov.id .. ']`' table.insert(t, '*Governor:* ' .. s) end local modstring = '' - for k,v in pairs(group.mods) do - modstring = modstring .. mod_format(k) + for k,_ in pairs(group.mods) do + modstring = modstring .. administration.mod_format(self, k) end if modstring ~= '' then table.insert(t, '*Moderators:*\n' .. modstring:trim()) @@ -221,962 +232,896 @@ local get_desc = function(chat_id) end -update_desc = function(chat) - local group = database.administration.groups[tostring(chat)] +function administration:update_desc(chat) + local group = self.database.administration.groups[tostring(chat)] local desc = 'Welcome to ' .. group.name .. '!\n' if group.motd then desc = desc .. group.motd .. '\n' end if group.governor then - local gov = database.users[tostring(group.governor)] - desc = desc .. '\nGovernor: ' .. build_name(gov.first_name, gov.last_name) .. ' [' .. gov.id .. ']\n' + local gov = self.database.users[tostring(group.governor)] + desc = desc .. '\nGovernor: ' .. utilities.build_name(gov.first_name, gov.last_name) .. ' [' .. gov.id .. ']\n' end - local s = '\n/desc@' .. bot.username .. ' for more information.' + local s = '\n/desc@' .. self.info.username .. ' for more information.' desc = desc:sub(1, 250-s:len()) .. s drua.channel_set_about(chat, desc) end -local commands = { +function administration.init_command(self_) + administration.commands = { - { -- antisquig - triggers = { - '[\216-\219][\128-\191]', -- arabic - '‮', -- rtl - '‏', -- other rtl + { -- antisquig + triggers = { + '[\216-\219][\128-\191]', -- arabic + '‮', -- rtl + '‏', -- other rtl + }, + + privilege = 0, + interior = true, + + action = function(self, msg, group) + if administration.get_rank(self, msg.from.id, msg.chat.id) > 1 then + return true + end + if not group.flags[2] then + return true + end + drua.kick_user(msg.chat.id, msg.from.id) + local output = administration.flags[2].kicked:gsub('GROUPNAME', msg.chat.title) + bindings.sendMessage(self, msg.from.id, output) + end }, - privilege = 0, - interior = true, + { -- generic + triggers = { '' }, - action = function(msg, group) - if get_rank(msg.from.id, msg.chat.id) > 1 then - return true - end - if not group.flags[2] then - return true - end - drua.kick_user(msg.chat.id, msg.from.id) - local output = flags[2].kicked:gsub('GROUPNAME', msg.chat.title) - sendMessage(msg.from.id, output) - end - }, + privilege = 0, + interior = true, - { -- generic - triggers = { '' }, + action = function(self, msg, group) - privilege = 0, - interior = true, - - action = function(msg, group) - - local rank = get_rank(msg.from.id, msg.chat.id) - - -- banned - if rank == 0 then - drua.kick_user(msg.chat.id, msg.from.id) - sendMessage(msg.from.id, 'Sorry, you are banned from ' .. msg.chat.title .. '.') - return - end - - if rank < 2 then - - -- antisquig Strict - if group.flags[3] == true then - if msg.from.name:match('[\216-\219][\128-\191]') or msg.from.name:match('‮') or msg.from.name:match('‏') then - drua.kick_user(msg.chat.id, msg.from.id) - local output = flags[3].kicked:gsub('GROUPNAME', msg.chat.title) - sendMessage(msg.from.id, output) - return - end - end - - -- antiflood - if group.flags[5] == true then - if not group.antiflood then - group.antiflood = JSON.decode(JSON.encode(antiflood)) - end - if not admin_temp.flood[msg.chat.id_str] then - admin_temp.flood[msg.chat.id_str] = {} - end - if not admin_temp.flood[msg.chat.id_str][msg.from.id_str] then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = 0 - end - if msg.sticker then -- Thanks Brazil for discarding switches. - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.sticker - elseif msg.photo then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.photo - elseif msg.document then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.document - elseif msg.audio then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.audio - elseif msg.contact then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.contact - elseif msg.video then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.video - elseif msg.location then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.location - elseif msg.voice then - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.voice - else - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.text - end - if admin_temp.flood[msg.chat.id_str][msg.from.id_str] > 99 then - drua.kick_user(msg.chat.id, msg.from.id) - local output = flags[5].kicked:gsub('GROUPNAME', msg.chat.title) - sendMessage(msg.from.id, output) - admin_temp.flood[msg.chat.id_str][msg.from.id_str] = nil - return - end - end - - end - - if msg.new_chat_participant then - - msg.new_chat_participant.name = build_name(msg.new_chat_participant.first_name, msg.new_chat_participant.last_name) + local rank = administration.get_rank(self, msg.from.id, msg.chat.id) -- banned - if get_rank(msg.new_chat_participant.id, msg.chat.id) == 0 then - drua.kick_user(msg.chat.id, msg.new_chat_participant.id) - sendMessage(msg.new_chat_participant.id, 'Sorry, you are banned from ' .. msg.chat.title .. '.') + if rank == 0 then + drua.kick_user(msg.chat.id, msg.from.id) + bindings.sendMessage(self, msg.from.id, 'Sorry, you are banned from ' .. msg.chat.title .. '.') return end - -- antisquig Strict - if group.flags[3] == true then - if msg.new_chat_participant.name:match('[\216-\219][\128-\191]') or msg.new_chat_participant.name:match('‮') or msg.new_chat_participant.name:match('‏') then + if rank < 2 then + + -- antisquig Strict + if group.flags[3] == true then + if msg.from.name:match('[\216-\219][\128-\191]') or msg.from.name:match('‮') or msg.from.name:match('‏') then + drua.kick_user(msg.chat.id, msg.from.id) + local output = administration.flags[3].kicked:gsub('GROUPNAME', msg.chat.title) + bindings.sendMessage(self, msg.from.id, output) + return + end + end + + -- antiflood + if group.flags[5] == true then + if not group.antiflood then + group.antiflood = JSON.decode(JSON.encode(administration.antiflood)) + end + if not self.admin_temp.flood[msg.chat.id_str] then + self.admin_temp.flood[msg.chat.id_str] = {} + end + if not self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = 0 + end + if msg.sticker then -- Thanks Brazil for discarding switches. + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.sticker + elseif msg.photo then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.photo + elseif msg.document then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.document + elseif msg.audio then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.audio + elseif msg.contact then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.contact + elseif msg.video then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.video + elseif msg.location then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.location + elseif msg.voice then + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.voice + else + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] + group.antiflood.text + end + if self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] > 99 then + drua.kick_user(msg.chat.id, msg.from.id) + local output = administration.flags[5].kicked:gsub('GROUPNAME', msg.chat.title) + bindings.sendMessage(msg.from.id, output) + self.admin_temp.flood[msg.chat.id_str][msg.from.id_str] = nil + return + end + end + + end + + if msg.new_chat_participant then + + msg.new_chat_participant.name = utilities.build_name(msg.new_chat_participant.first_name, msg.new_chat_participant.last_name) + + -- banned + if administration.get_rank(self, msg.new_chat_participant.id, msg.chat.id) == 0 then drua.kick_user(msg.chat.id, msg.new_chat_participant.id) - local output = flags[3].kicked:gsub('GROUPNAME', msg.chat.title) - sendMessage(msg.new_chat_participant.id, output) + bindings.sendMessage(self, msg.new_chat_participant.id, 'Sorry, you are banned from ' .. msg.chat.title .. '.') return end - end - -- antibot - if msg.new_chat_participant.username and msg.new_chat_participant.username:match('bot$') then - if rank < 2 and group.flags[4] == true then - drua.kick_user(msg.chat.id, msg.new_chat_participant.id) + -- antisquig Strict + if group.flags[3] == true then + if msg.new_chat_participant.name:match('[\216-\219][\128-\191]') or msg.new_chat_participant.name:match('‮') or msg.new_chat_participant.name:match('‏') then + drua.kick_user(msg.chat.id, msg.new_chat_participant.id) + local output = administration.flags[3].kicked:gsub('GROUPNAME', msg.chat.title) + bindings.sendMessage(self, msg.new_chat_participant.id, output) + return + end + end + + -- antibot + if msg.new_chat_participant.username and msg.new_chat_participant.username:match('bot$') then + if rank < 2 and group.flags[4] == true then + drua.kick_user(msg.chat.id, msg.new_chat_participant.id) + return + end + else + local output = administration.get_desc(self, msg.chat.id) + bindings.sendMessage(self, msg.new_chat_participant.id, output, true, nil, true) return end - else - local output = get_desc(msg.chat.id) - sendMessage(msg.new_chat_participant.id, output, true, nil, true) - return - end - elseif msg.new_chat_title then + elseif msg.new_chat_title then - if rank < 3 then - drua.rename_chat(msg.chat.id, group.name) - else - group.name = msg.new_chat_title - if group.grouptype == 'supergroup' then - update_desc(msg.chat.id) - end - end - return - - elseif msg.new_chat_photo then - - if group.grouptype == 'group' then if rank < 3 then - drua.set_photo(msg.chat.id, group.photo) + drua.rename_chat(msg.chat.id, group.name) + else + group.name = msg.new_chat_title + if group.grouptype == 'supergroup' then + administration.update_desc(msg.chat.id) + end + end + return + + elseif msg.new_chat_photo then + + if group.grouptype == 'group' then + if rank < 3 then + drua.set_photo(msg.chat.id, group.photo) + else + group.photo = drua.get_photo(msg.chat.id) + end else group.photo = drua.get_photo(msg.chat.id) end - else - group.photo = drua.get_photo(msg.chat.id) - end - return + return - elseif msg.delete_chat_photo then + elseif msg.delete_chat_photo then - if group.grouptype == 'group' then - if rank < 3 then - drua.set_photo(msg.chat.id, group.photo) + if group.grouptype == 'group' then + if rank < 3 then + drua.set_photo(msg.chat.id, group.photo) + else + group.photo = nil + end else group.photo = nil end - else - group.photo = nil - end - return - - end - - -- Last active time for group listing. - for i,v in pairs(database.administration.activity) do - if v == msg.chat.id_str then - table.remove(database.administration.activity, i) - table.insert(database.administration.activity, 1, msg.chat.id_str) - end - end - - return true - - end - }, - - { -- groups - triggers = { - '^/groups$', - '^/groups@'..bot.username - }, - - command = 'groups', - privilege = 1, - interior = false, - - action = function(msg) - local output = '' - for i,v in ipairs(database.administration.activity) do - local group = database.administration.groups[v] - if not group.flags[1] then -- no unlisted groups - if group.link then - output = output .. '• [' .. group.name .. '](' .. group.link .. ')\n' - else - output = output .. '• ' .. group.name .. '\n' - end - end - end - if output == '' then - output = 'There are currently no listed groups.' - else - output = '*Groups:*\n' .. output - end - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- ahelp - triggers = { - '^/ahelp$', - '^/ahelp@'..bot.username - }, - - command = 'ahelp', - privilege = 1, - interior = false, - - action = function(msg) - local rank = get_rank(msg.from.id, msg.chat.id) - local output = '*Commands for ' .. ranks[rank] .. ':*\n' - for i = 1, rank do - for ind, val in ipairs(admin_temp.help[i]) do - output = output .. '• /' .. val .. '\n' - end - end - if sendMessage(msg.from.id, output, true, nil, true) then - if msg.from.id ~= msg.chat.id then - sendReply(msg, 'I have sent you the requested information in a private message.') - end - else - sendMessage(msg.chat.id, output, true, nil, true) - end - end - }, - - { -- alist - triggers = { - '^/ops$', - '^/ops@'..bot.username, - '^/oplist$', - '^/oplist@'..bot.username - }, - - command = 'ops', - privilege = 1, - interior = true, - - action = function(msg, group) - local modstring = '' - for k,v in pairs(group.mods) do - modstring = modstring .. mod_format(k) - end - if modstring ~= '' then - modstring = '*Moderators for* _' .. msg.chat.title .. '_ *:*\n' .. modstring - end - local govstring = '' - if group.governor then - local gov = database.users[tostring(group.governor)] - govstring = '*Governor:* ' .. build_name(gov.first_name, gov.last_name):md_escape() .. ' `[' .. gov.id .. ']`' - end - local output = modstring:trim() ..'\n\n' .. govstring:trim() - if output == '\n\n' then - output = 'There are currently no moderators for this group.' - end - sendMessage(msg.chat.id, output, true, nil, true) - end - - }, - - { -- desc - triggers = { - '^/desc[ription]*$', - '^/desc[ription]*@'..bot.username - }, - - command = 'description', - privilege = 1, - interior = true, - - action = function(msg) - local output = get_desc(msg.chat.id) - if sendMessage(msg.from.id, output, true, nil, true) then - if msg.from.id ~= msg.chat.id then - sendReply(msg, 'I have sent you the requested information in a private message.') - end - else - sendMessage(msg.chat.id, output, true, nil, true) - end - end - }, - - { -- rules - triggers = { - '^/rules?', - '^/rules?@'..bot.username - }, - - command = 'rules', - privilege = 1, - interior = true, - - action = function(msg, group) - local output - local input = get_word(msg.text_lower, 2) - input = tonumber(input) - if #group.rules > 0 then - if input and group.rules[input] then - output = '*' .. input .. '.* ' .. group.rules[input] - else - output = '*Rules for* _' .. msg.chat.title .. '_ *:*\n' - for i,v in ipairs(group.rules) do - output = output .. '*' .. i .. '.* ' .. v .. '\n' - end - end - else - output = 'No rules have been set for ' .. msg.chat.title .. '.' - end - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- motd - triggers = { - '^/motd$', - '^/motd@'..bot.username - }, - - command = 'motd', - privilege = 1, - interior = true, - - action = function(msg, group) - local output = 'No MOTD has been set for ' .. msg.chat.title .. '.' - if group.motd then - output = '*MOTD for* _' .. msg.chat.title .. '_ *:*\n' .. group.motd - end - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- link - triggers = { - '^/link$', - '^/link@'..bot.username - }, - - command = 'link', - privilege = 1, - interior = true, - - action = function(msg, group) - local output = 'No link has been set for ' .. msg.chat.title .. '.' - if group.link then - output = '[' .. msg.chat.title .. '](' .. group.link .. ')' - end - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- kick - triggers = { - '^/kick[@'..bot.username..']*' - }, - - command = 'kick ', - privilege = 2, - interior = true, - - action = function(msg) - local target = get_target(msg) - if target.err then - sendReply(msg, target.err) - return - elseif target.rank > 1 then - sendReply(msg, target.name .. ' is too privileged to be kicked.') - return - end - drua.kick_user(msg.chat.id, target.id) - sendMessage(msg.chat.id, target.name .. ' has been kicked.') - end - }, - - { -- ban - triggers = { - '^/ban', - '^/unban' - }, - - command = 'ban ', - privilege = 2, - interior = true, - - action = function(msg, group) - local target = get_target(msg) - if target.err then - sendReply(msg, target.err) - return - end - if target.rank > 1 then - sendReply(msg, target.name .. ' is too privileged to be banned.') - return - end - if group.bans[target.id_str] then - group.bans[target.id_str] = nil - sendReply(msg, target.name .. ' has been unbanned.') - else - group.bans[target.id_str] = true - drua.kick_user(msg.chat.id, target.id) - sendReply(msg, target.name .. ' has been banned.') - end - end - }, - - { -- changerule - triggers = { - '^/changerule', - '^/changerule@' .. bot.username - }, - - command = 'changerule ', - privilege = 3, - interior = true, - - action = function(msg, group) - local usage = 'usage: `/changerule `\n`/changerule -- `deletes.' - local input = msg.text:input() - if not input then - sendMessage(msg.chat.id, usage, true, msg.message_id, true) - return - end - local rule_num = input:match('^%d+') - if not rule_num then - local output = 'Please specify which rule you want to change.\n' .. usage - sendMessage(msg.chat.id, output, true, msg.message_id, true) - return - end - rule_num = tonumber(rule_num) - local rule_new = input:input() - if not rule_new then - local output = 'Please specify the new rule.\n' .. usage - sendMessage(msg.chat.id, output, true, msg.message_id, true) - return - end - if not group.rules then - local output = 'Sorry, there are no rules to change. Please use /setrules.\n' .. usage - sendMessage(msg.chat.id, output, true, msg.message_id, true) - return - end - if not group.rules[rule_num] then - rule_num = #group.rules + 1 - end - if rule_new == '--' or rule_new == '—' then - if group.rules[rule_num] then - table.remove(group.rules, rule_num) - sendReply(msg, 'That rule has been deleted.') - else - sendReply(msg, 'There is no rule with that number.') - end - return - end - group.rules[rule_num] = rule_new - local output = '*' .. rule_num .. '*. ' .. rule_new - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- setrules - triggers = { - '^/setrules[@'..bot.username..']*' - }, - - command = 'setrules ', - privilege = 3, - interior = true, - - action = function(msg, group) - local input = msg.text:match('^/setrules[@'..bot.username..']*(.+)') - if not input then - sendMessage(msg.chat.id, '```\n/setrules [rule]\n\n[rule]\n...\n```', true, msg.message_id, true) - return - elseif input == ' --' or input == ' —' then - group.rules = {} - sendReply(msg, 'The rules have been cleared.') - return - end - group.rules = {} - input = input:trim() .. '\n' - local output = '*Rules for* _' .. msg.chat.title .. '_ *:*\n' - local i = 1 - for l in input:gmatch('(.-)\n') do - output = output .. '*' .. i .. '.* ' .. l .. '\n' - i = i + 1 - table.insert(group.rules, l:trim()) - end - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- setmotd - triggers = { - '^/setmotd[@'..bot.username..']*' - }, - - command = 'setmotd ', - privilege = 3, - interior = true, - - action = function(msg, group) - local input = msg.text:input() - if not input then - if msg.reply_to_message and msg.reply_to_message.text then - input = msg.reply_to_message.text - else - sendReply(msg, 'Please specify the new message of the day.') return + + end + + -- Last active time for group listing. + for i,v in pairs(self.database.administration.activity) do + if v == msg.chat.id_str then + table.remove(self.database.administration.activity, i) + table.insert(self.database.administration.activity, 1, msg.chat.id_str) + end + end + + return true + + end + }, + + { -- groups + triggers = utilities.triggers(self_.info.username):t('groups').table, + + command = 'groups', + privilege = 1, + interior = false, + + action = function(self, msg) + local output = '' + for _,v in ipairs(self.database.administration.activity) do + local group = self.database.administration.groups[v] + if not group.flags[1] then -- no unlisted groups + if group.link then + output = output .. '• [' .. group.name .. '](' .. group.link .. ')\n' + else + output = output .. '• ' .. group.name .. '\n' + end + end + end + if output == '' then + output = 'There are currently no listed groups.' + else + output = '*Groups:*\n' .. output + end + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- ahelp + triggers = utilities.triggers(self_.info.username):t('ahelp').table, + + command = 'ahelp', + privilege = 1, + interior = false, + + action = function(self, msg) + local rank = administration.get_rank(self, msg.from.id, msg.chat.id) + local output = '*Commands for ' .. administration.ranks[rank] .. ':*\n' + for i = 1, rank do + for _, val in ipairs(self.admin_temp.help[i]) do + output = output .. '• /' .. val .. '\n' + end + end + if bindings.sendMessage(self, msg.from.id, output, true, nil, true) then + if msg.from.id ~= msg.chat.id then + bindings.sendReply(self, msg, 'I have sent you the requested information in a private message.') + end + else + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) end end - if input == '--' or input == '—' then - group.motd = nil - sendReply(msg, 'The MOTD has been cleared.') - else - input = input:trim() - group.motd = input - local output = '*MOTD for* _' .. msg.chat.title .. '_ *:*\n' .. input - sendMessage(msg.chat.id, output, true, nil, true) - end - if group.grouptype == 'supergroup' then - update_desc(msg.chat.id) - end - end - }, - - { -- setlink - triggers = { - '^/setlink[@'..bot.username..']*' }, - command = 'setlink ', - privilege = 3, - interior = true, + { -- alist + triggers = utilities.triggers(self_.info.username):t('ops'):t('oplist').table, - action = function(msg, group) - local input = msg.text:input() - if not input then - sendReply(msg, 'Please specify the new link.') - return - elseif input == '--' or input == '—' then - group.link = drua.export_link(msg.chat.id) - sendReply(msg, 'The link has been regenerated.') - return + command = 'ops', + privilege = 1, + interior = true, + + action = function(self, msg, group) + local modstring = '' + for k,_ in pairs(group.mods) do + modstring = modstring .. administration.mod_format(self, k) + end + if modstring ~= '' then + modstring = '*Moderators for* _' .. msg.chat.title .. '_ *:*\n' .. modstring + end + local govstring = '' + if group.governor then + local gov = self.database.users[tostring(group.governor)] + govstring = '*Governor:* ' .. utilities.md_escape(utilities.build_name(gov.first_name, gov.last_name)) .. ' `[' .. gov.id .. ']`' + end + local output = modstring:trim() ..'\n\n' .. govstring:trim() + if output == '\n\n' then + output = 'There are currently no moderators for this group.' + end + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) end - group.link = input - local output = '[' .. msg.chat.title .. '](' .. input .. ')' - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - { -- alist - triggers = { - '^/alist$', - '^/alist@'..bot.username }, - command = 'alist', - privilege = 3, - interior = true, + { -- desc + triggers = utilities.triggers(self_.info.username):t('desc'):t('description').table, - action = function(msg) - local output = '*Administrators:*\n' - output = output .. mod_format(config.admin):gsub('\n', ' ★\n') - for k,v in pairs(database.administration.admins) do - output = output .. mod_format(k) + command = 'description', + privilege = 1, + interior = true, + + action = function(self, msg) + local output = administration.get_desc(self, msg.chat.id) + if bindings.sendMessage(self, msg.from.id, output, true, nil, true) then + if msg.from.id ~= msg.chat.id then + bindings.sendReply(self, msg, 'I have sent you the requested information in a private message.') + end + else + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end end - sendMessage(msg.chat.id, output, true, nil, true) - end - }, - - { -- flags - triggers = { - '^/flags?' }, - command = 'flag ', - privilege = 3, - interior = true, + { -- rules + triggers = utilities.triggers(self_.info.username):t('rules?', true).table, - action = function(msg, group) - local input = msg.text:input() - if input then - input = get_word(input, 1) + command = 'rules', + privilege = 1, + interior = true, + + action = function(self, msg, group) + local output + local input = utilities.get_word(msg.text_lower, 2) input = tonumber(input) - if not input or not flags[input] then input = false end - end - if not input then - local output = '*Flags for* _' .. msg.chat.title .. '_ *:*\n' - for i,v in ipairs(flags) do - local status = group.flags[i] or false - output = output .. '`[' .. i .. ']` *' .. v.name .. '*` = ' .. tostring(status) .. '`\n• ' .. v.desc .. '\n' - end - sendMessage(msg.chat.id, output, true, nil, true) - return - end - local output - if group.flags[input] == true then - group.flags[input] = false - sendReply(msg, flags[input].disabled) - else - group.flags[input] = true - sendReply(msg, flags[input].enabled) - end - end - }, - - { -- antiflood - triggers = { - '^/antiflood' - }, - - command = 'antiflood ', - privilege = 3, - interior = true, - - action = function(msg, group) - if not group.flags[5] then - sendMessage(msg.chat.id, 'antiflood is not enabled. Use `/flag 5` to enable it.', true, nil, true) - return - end - if not group.antiflood then - group.antiflood = JSON.decode(JSON.encode(antiflood)) - end - local input = msg.text_lower:input() - local output - if input then - local key, val = input:match('(%a+) (%d+)') - if not group.antiflood[key] or not tonumber(val) then - output = 'Not a valid message type or number.' + if #group.rules > 0 then + if input and group.rules[input] then + output = '*' .. input .. '.* ' .. group.rules[input] + else + output = '*Rules for* _' .. msg.chat.title .. '_ *:*\n' + for i,v in ipairs(group.rules) do + output = output .. '*' .. i .. '.* ' .. v .. '\n' + end + end else - group.antiflood[key] = val - output = '*' .. key:gsub('^%l', string.upper) .. '* messages are now worth *' .. val .. '* points.' - end - else - output = 'usage: `/antiflood `\nexample: `/antiflood text 5`\nUse this command to configure the point values for each message type. When a user reaches 100 points, he is kicked. The points are reset each minute. The current values are:\n' - for k,v in pairs(group.antiflood) do - output = output .. '*'..k..':* `'..v..'`\n' + output = 'No rules have been set for ' .. msg.chat.title .. '.' end + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) end - sendMessage(msg.chat.id, output, true, msg.message_id, true) - end - }, - - { -- mod - triggers = { - '^/mod', - '^/demod' }, - command = 'mod ', - privilege = 3, - interior = true, + { -- motd + triggers = utilities.triggers(self_.info.username):t('motd').table, - action = function(msg, group) - local target = get_target(msg) - if target.err then - sendReply(msg, target.err) - return - end - if group.mods[target.id_str] then - if group.grouptype == 'supergroup' then - drua.channel_set_admin(msg.chat.id, target.id, 0) + command = 'motd', + privilege = 1, + interior = true, + + action = function(self, msg, group) + local output = 'No MOTD has been set for ' .. msg.chat.title .. '.' + if group.motd then + output = '*MOTD for* _' .. msg.chat.title .. '_ *:*\n' .. group.motd end - group.mods[target.id_str] = nil - sendReply(msg, target.name .. ' is no longer a moderator.') - else - if target.rank > 2 then - sendReply(msg, target.name .. ' is greater than a moderator.') + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- link + triggers = utilities.triggers(self_.info.username):t('link').table, + + command = 'link', + privilege = 1, + interior = true, + + action = function(self, msg, group) + local output = 'No link has been set for ' .. msg.chat.title .. '.' + if group.link then + output = '[' .. msg.chat.title .. '](' .. group.link .. ')' + end + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- kick + triggers = utilities.triggers(self_.info.username):t('kick', true).table, + + command = 'kick ', + privilege = 2, + interior = true, + + action = function(self, msg) + local target = administration.get_target(self, msg) + if target.err then + bindings.sendReply(self, msg, target.err) + return + elseif target.rank > 1 then + bindings.sendReply(self, msg, target.name .. ' is too privileged to be kicked.') return end - if group.grouptype == 'supergroup' then - drua.channel_set_admin(msg.chat.id, target.id, 2) - end - group.mods[target.id_str] = true - sendReply(msg, target.name .. ' is now a moderator.') + drua.kick_user(msg.chat.id, target.id) + bindings.sendMessage(self, msg.chat.id, target.name .. ' has been kicked.') end - end - }, - - { -- gov - triggers = { - '^/gov', - '^/degov' }, - command = 'gov ', - privilege = 4, - interior = true, + { -- ban + triggers = utilities.triggers(self_.info.username):t('ban', true):t('unban', true).table, - action = function(msg, group) - local target = get_target(msg) - if target.err then - sendReply(msg, target.err) - return + command = 'ban ', + privilege = 2, + interior = true, + + action = function(self, msg, group) + local target = administration.get_target(self, msg) + if target.err then + bindings.sendReply(self, msg, target.err) + return + end + if target.rank > 1 then + bindings.sendReply(self, msg, target.name .. ' is too privileged to be banned.') + return + end + if group.bans[target.id_str] then + group.bans[target.id_str] = nil + bindings.sendReply(self, msg, target.name .. ' has been unbanned.') + else + group.bans[target.id_str] = true + drua.kick_user(msg.chat.id, target.id) + bindings.sendReply(self, msg, target.name .. ' has been banned.') + end end - if group.governor and group.governor == target.id then - if group.grouptype == 'supergroup' then - drua.channel_set_admin(msg.chat.id, target.id, 0) + }, + + { -- changerule + triggers = utilities.triggers(self_.info.username):t('changerule', true).table, + + command = 'changerule ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + local usage = 'usage: `/changerule `\n`/changerule -- `deletes.' + local input = utilities.input(msg.text) + if not input then + bindings.sendMessage(self, msg.chat.id, usage, true, msg.message_id, true) + return end - group.governor = config.admin - sendReply(msg, target.name .. ' is no longer the governor.') - else - if group.grouptype == 'supergroup' then - if group.governor then - drua.channel_set_admin(msg.chat.id, group.governor, 0) + local rule_num = input:match('^%d+') + if not rule_num then + local output = 'Please specify which rule you want to change.\n' .. usage + bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) + return + end + rule_num = tonumber(rule_num) + local rule_new = utilities.input(input) + if not rule_new then + local output = 'Please specify the new rule.\n' .. usage + bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) + return + end + if not group.rules then + local output = 'Sorry, there are no rules to change. Please use /setrules.\n' .. usage + bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) + return + end + if not group.rules[rule_num] then + rule_num = #group.rules + 1 + end + if rule_new == '--' or rule_new == '—' then + if group.rules[rule_num] then + table.remove(group.rules, rule_num) + bindings.sendReply(self, msg, 'That rule has been deleted.') + else + bindings.sendReply(self, msg, 'There is no rule with that number.') end - drua.channel_set_admin(msg.chat.id, target.id, 2) + return end - if target.rank == 2 then + group.rules[rule_num] = rule_new + local output = '*' .. rule_num .. '*. ' .. rule_new + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- setrules + triggers = utilities.triggers(self_.info.username):t('setrules', true).table, + + command = 'setrules ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + local input = msg.text:match('^/setrules[@'..self.info.username..']*(.+)') + if not input then + bindings.sendMessage(self, msg.chat.id, '```\n/setrules [rule]\n\n[rule]\n...\n```', true, msg.message_id, true) + return + elseif input == ' --' or input == ' —' then + group.rules = {} + bindings.sendReply(self, msg, 'The rules have been cleared.') + return + end + group.rules = {} + input = input:trim() .. '\n' + local output = '*Rules for* _' .. msg.chat.title .. '_ *:*\n' + local i = 1 + for l in input:gmatch('(.-)\n') do + output = output .. '*' .. i .. '.* ' .. l .. '\n' + i = i + 1 + table.insert(group.rules, l:trim()) + end + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- setmotd + triggers = utilities.triggers(self_.info.username):t('setmotd', true).table, + + command = 'setmotd ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + local input = utilities.input(msg.text) + if not input then + if msg.reply_to_message and msg.reply_to_message.text then + input = msg.reply_to_message.text + else + bindings.sendReply(self, msg, 'Please specify the new message of the day.') + return + end + end + if input == '--' or input == '—' then + group.motd = nil + bindings.sendReply(self, msg, 'The MOTD has been cleared.') + else + input = input:trim() + group.motd = input + local output = '*MOTD for* _' .. msg.chat.title .. '_ *:*\n' .. input + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + if group.grouptype == 'supergroup' then + administration.update_desc(self, msg.chat.id) + end + end + }, + + { -- setlink + triggers = utilities.triggers(self_.info.username):t('setlink', true).table, + + command = 'setlink ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + local input = utilities.input(msg.text) + if not input then + bindings.sendReply(self, msg, 'Please specify the new link.') + return + elseif input == '--' or input == '—' then + group.link = drua.export_link(msg.chat.id) + bindings.sendReply(self, msg, 'The link has been regenerated.') + return + end + group.link = input + local output = '[' .. msg.chat.title .. '](' .. input .. ')' + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- alist + triggers = utilities.triggers(self_.info.username):t('alist').table, + + command = 'alist', + privilege = 3, + interior = true, + + action = function(self, msg) + local output = '*Administrators:*\n' + output = output .. administration.mod_format(self, self.config.admin):gsub('\n', ' ★\n') + for id,_ in pairs(self.database.administration.admins) do + output = output .. administration.mod_format(self, id) + end + bindings.sendMessage(self, msg.chat.id, output, true, nil, true) + end + }, + + { -- flags + triggers = utilities.triggers(self_.info.username):t('flags?', true).table, + + command = 'flag ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + local input = utilities.input(msg.text) + if input then + input = utilities.get_word(input, 1) + input = tonumber(input) + if not input or not administration.flags[input] then input = false end + end + if not input then + local output = '*Flags for* _' .. msg.chat.title .. '_ *:*\n' + for i,v in ipairs(administration.flags) do + local status = group.flags[i] or false + output = output .. '`[' .. i .. ']` *' .. v.name .. '*` = ' .. tostring(status) .. '`\n• ' .. v.desc .. '\n' + end + bindings.sendMessage(msg.chat.id, output, true, nil, true) + return + end + if group.flags[input] == true then + group.flags[input] = false + bindings.sendReply(self, msg, administration.flags[input].disabled) + else + group.flags[input] = true + bindings.sendReply(self, msg, administration.flags[input].enabled) + end + end + }, + + { -- antiflood + triggers = utilities.triggers(self_.info.username):t('antiflood', true).table, + + command = 'antiflood ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + if not group.flags[5] then + bindings.sendMessage(self, msg.chat.id, 'antiflood is not enabled. Use `/flag 5` to enable it.', true, nil, true) + return + end + if not group.antiflood then + group.antiflood = JSON.decode(JSON.encode(administration.antiflood)) + end + local input = utilities.input(msg.text_lower) + local output + if input then + local key, val = input:match('(%a+) (%d+)') + if not group.antiflood[key] or not tonumber(val) then + output = 'Not a valid message type or number.' + else + group.antiflood[key] = val + output = '*' .. key:gsub('^%l', string.upper) .. '* messages are now worth *' .. val .. '* points.' + end + else + output = 'usage: `/antiflood `\nexample: `/antiflood text 5`\nUse this command to configure the point values for each message type. When a user reaches 100 points, he is kicked. The points are reset each minute. The current values are:\n' + for k,v in pairs(group.antiflood) do + output = output .. '*'..k..':* `'..v..'`\n' + end + end + bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) + end + }, + + { -- mod + triggers = utilities.triggers(self_.info.username):t('mod', true):t('demod', true).table, + + command = 'mod ', + privilege = 3, + interior = true, + + action = function(self, msg, group) + local target = administration.get_target(self, msg) + if target.err then + bindings.sendReply(self, msg, target.err) + return + end + if group.mods[target.id_str] then + if group.grouptype == 'supergroup' then + drua.channel_set_admin(msg.chat.id, target.id, 0) + end group.mods[target.id_str] = nil + bindings.sendReply(self, msg, target.name .. ' is no longer a moderator.') + else + if target.rank > 2 then + bindings.sendReply(self, msg, target.name .. ' is greater than a moderator.') + return + end + if group.grouptype == 'supergroup' then + drua.channel_set_admin(msg.chat.id, target.id, 2) + end + group.mods[target.id_str] = true + bindings.sendReply(self, msg, target.name .. ' is now a moderator.') end - group.governor = target.id - sendReply(msg, target.name .. ' is the new governor.') end - if group.grouptype == 'supergroup' then - update_desc(msg.chat.id) - end - end - }, - - { -- hammer - triggers = { - '^/hammer', - '^/unhammer' }, - command = 'hammer ', - privilege = 4, - interior = false, + { -- gov + triggers = utilities.triggers(self_.info.username):t('gov', true):t('degov', true).table, - action = function(msg) - local target = get_target(msg) - if target.err then - sendReply(msg, target.err) - return - end - if target.rank > 3 then - sendReply(msg, target.name .. ' is too privileged to be globally banned.') - return - end - if database.blacklist[target.id_str] then - database.blacklist[target.id_str] = nil - sendReply(msg, target.name .. ' has been globally unbanned.') - else - database.blacklist[target.id_str] = true - for k,v in pairs(database.administration.groups) do - drua.kick_user(k, target.id) - end - sendReply(msg, target.name .. ' has been globally banned.') - end - end - }, + command = 'gov ', + privilege = 4, + interior = true, - { -- admin - triggers = { - '^/admin', - '^/deadmin' - }, - - command = 'admin 3 then + bindings.sendReply(self, msg, target.name .. ' is too privileged to be globally banned.') + return + end + if self.database.blacklist[target.id_str] then + self.database.blacklist[target.id_str] = nil + bindings.sendReply(self, msg, target.name .. ' has been globally unbanned.') + else + self.database.blacklist[target.id_str] = true + for k,_ in pairs(self.database.administration.groups) do + drua.kick_user(k, target.id) + end + bindings.sendReply(self, msg, target.name .. ' has been globally banned.') + end + end }, - command = 'gremove \\[chat]', - privilege = 5, - interior = true, + { -- admin + triggers = utilities.triggers(self_.info.username):t('admin', true):t('deadmin', true).table, - action = function(msg) - local input = msg.text:input() or msg.chat.id_str - if database.administration.groups[input] then - database.administration.groups[input] = nil - for i,v in ipairs(database.administration.activity) do - if v == input then - table.remove(database.administration.activity, i) + command = 'admin ', + privilege = 5, + interior = false, + + action = function(self, msg) + local target = administration.get_target(self, msg) + if target.err then + bindings.sendReply(self, msg, target.err) + return + end + if self.database.administration.admins[target.id_str] then + self.database.administration.admins[target.id_str] = nil + bindings.sendReply(self, msg, target.name .. ' is no longer an administrator.') + else + if target.rank == 5 then + bindings.sendReply(self, msg, target.name .. ' is greater than an administrator.') + return + end + for _,group in pairs(self.database.administration.groups) do + group.mods[target.id_str] = nil + end + self.database.administration.admins[target.id_str] = true + bindings.sendReply(self, msg, target.name .. ' is now an administrator.') + end + end + }, + + { -- gadd + triggers = utilities.triggers(self_.info.username):t('gadd').table, + + command = 'gadd', + privilege = 5, + interior = false, + + action = function(self, msg) + if self.database.administration.groups[msg.chat.id_str] then + bindings.sendReply(msg, 'I am already administrating this group.') + return + end + self.database.administration.groups[msg.chat.id_str] = { + mods = {}, + governor = msg.from.id, + bans = {}, + flags = {}, + rules = {}, + grouptype = msg.chat.type, + name = msg.chat.title, + link = drua.export_link(msg.chat.id), + photo = drua.get_photo(msg.chat.id), + founded = os.time() + } + for i,_ in ipairs(administration.flags) do + self.database.administration.groups[msg.chat.id_str].flags[i] = false + end + table.insert(self.database.administration.activity, msg.chat.id_str) + bindings.sendReply(self, msg, 'I am now administrating this group.') + end + }, + + { -- grem + triggers = utilities.triggers(self_.info.username):t('grem', true):t('gremove', true).table, + + command = 'gremove \\[chat]', + privilege = 5, + interior = true, + + action = function(self, msg) + local input = utilities.input(msg.text) or msg.chat.id_str + if self.database.administration.groups[input] then + self.database.administration.groups[input] = nil + for i,v in ipairs(self.database.administration.activity) do + if v == input then + table.remove(self.database.administration.activity, i) + end + end + bindings.sendReply(self, msg, 'I am no longer administrating that group.') + else + bindings.sendReply(self, msg, 'I do not administrate that group.') + end + end + }, + + { -- glist + triggers = utilities.triggers(self_.info.username):t('list', false).table, + + command = 'glist', + privilege = 5, + interior = false, + + action = function(self, msg) + local output = '' + if utilities.table_size(self.database.administration.groups) > 0 then + for k,v in pairs(self.database.administration.groups) do + output = output .. '[' .. utilities.md_escape(v.name) .. '](' .. v.link .. ') `[' .. k .. ']`\n' + if v.governor then + local gov = self.database.users[tostring(v.governor)] + output = output .. '★ ' .. utilities.md_escape(utilities.build_name(gov.first_name, gov.last_name)) .. ' `[' .. gov.id .. ']`\n' + end + end + else + output = 'There are no groups.' + end + if bindings.sendMessage(self, msg.from.id, output, true, nil, true) then + if msg.from.id ~= msg.chat.id then + bindings.sendReply(self, msg, 'I have sent you the requested information in a private message.') end end - sendReply(msg, 'I am no longer administrating that group.') - else - sendReply(msg, 'I do not administrate that group.') end - end - }, - - { -- glist - triggers = { - '^/glist$', - '^/glist@'..bot.username }, - command = 'glist', - privilege = 5, - interior = false, + { -- broadcast + triggers = utilities.triggers(self_.info.username):t('broadcast', true).table, - action = function(msg) - local output = '' - if table_size(database.administration.groups) > 0 then - for k,v in pairs(database.administration.groups) do - output = output .. '[' .. v.name:md_escape() .. '](' .. v.link .. ') `[' .. k .. ']`\n' - if v.governor then - local gov = database.users[tostring(v.governor)] - output = output .. '★ ' .. build_name(gov.first_name, gov.last_name):md_escape() .. ' `[' .. gov.id .. ']`\n' - end + command = 'broadcast ', + privilege = 5, + interior = false, + + action = function(self, msg) + local input = utilities.input(msg.text) + if not input then + bindings.sendReply(self, msg, 'Give me something to broadcast.') + return end - else - output = 'There are no groups.' - end - if sendMessage(msg.from.id, output, true, nil, true) then - if msg.from.id ~= msg.chat.id then - sendReply(msg, 'I have sent you the requested information in a private message.') + input = '*Admin Broadcast:*\n' .. input + for id,_ in pairs(self.database.administration.groups) do + bindings.sendMessage(self, id, input, true, nil, true) end end - end - }, + } - { -- broadcast - triggers = { - '^/broadcast' - }, - - command = 'broadcast ', - privilege = 5, - interior = false, - - action = function(msg) - local input = msg.text:input() - if not input then - sendReply(msg, 'Give me something to broadcast.') - return - end - input = '*Admin Broadcast:*\n' .. input - for k,v in pairs(database.administration.groups) do - sendMessage(k, input, true, nil, true) - end - end } -} + -- Generate trigger table. + administration.triggers = {} + for _, command in ipairs(administration.commands) do + for _, trigger in ipairs(command.triggers) do + table.insert(administration.triggers, trigger) + end + end - -- Generate trigger table. -local triggers = {} -for i,v in ipairs(commands) do - for ind, val in ipairs(v.triggers) do - table.insert(triggers, val) + self_.database.administration.help = {} + for i,_ in ipairs(administration.ranks) do + self_.admin_temp.help[i] = {} + end + for _,v in ipairs(administration.commands) do + if v.command then + table.insert(self_.admin_temp.help[v.privilege], v.command) + end end end -database.administration.help = {} -for i,v in ipairs(ranks) do - admin_temp.help[i] = {} -end -for i,v in ipairs(commands) do - if v.command then - table.insert(admin_temp.help[v.privilege], v.command) - end -end - -local action = function(msg) - for i,v in ipairs(commands) do - for key,val in pairs(v.triggers) do - if msg.text_lower:match(val) then - if v.interior and not database.administration.groups[msg.chat.id_str] then +function administration:action(msg) + for _,command in ipairs(administration.commands) do + for _,trigger in pairs(command.triggers) do + if msg.text_lower:match(trigger) then + if command.interior and not self.database.administration.groups[msg.chat.id_str] then break end - if get_rank(msg.from.id, msg.chat.id) < v.privilege then + if administration.get_rank(self, msg.from.id, msg.chat.id) < command.privilege then break end - local res = v.action(msg, database.administration.groups[msg.chat.id_str]) + local res = command.action(self, msg, self.database.administration.groups[msg.chat.id_str]) if res ~= true then return res end @@ -1186,17 +1131,11 @@ local action = function(msg) return true end -local cron = function() - admin_temp.flood = {} +function administration:cron() + self.temp.flood = {} end -local command = 'groups' -local doc = '`Returns a list of administrated groups.\nUse /ahelp for more administrative commands.`' +administration.command = 'groups' +administration.doc = '`Returns a list of administrated groups.\nUse /ahelp for more administrative commands.`' -return { - action = action, - triggers = triggers, - cron = cron, - doc = doc, - command = command -} +return administration diff --git a/plugins/apod.lua b/plugins/apod.lua index ee6c90a..f8c56db 100755 --- a/plugins/apod.lua +++ b/plugins/apod.lua @@ -1,5 +1,13 @@ -local command = 'apod [date]' -local doc = [[``` +local apod = {} + +local HTTPS = require('ssl.https') +local JSON = require('cjson') +local URL = require('socket.url') +local bindings = require('bindings') +local utilities = require('utilities') + +apod.command = 'apod [date]' +apod.doc = [[``` /apod [query] Returns the Astronomy Picture of the Day. If the query is a date, in the format YYYY-MM-DD, the APOD of that day is returned. @@ -10,31 +18,29 @@ Returns the explanation of the APOD. Source: nasa.gov ```]] -local triggers = { - '^/apod[@'..bot.username..']*', - '^/apodhd[@'..bot.username..']*', - '^/apodtext[@'..bot.username..']*' -} +function apod:init() + apod.triggers = utilities.triggers(self.info.username) + :t('apod', true):t('apodhd', true):t('apodtext', true).table +end -local action = function(msg) +function apod:action(msg) - if not config.nasa_api_key then - config.nasa_api_key = 'DEMO_KEY' + if not self.config.nasa_api_key then + self.config.nasa_api_key = 'DEMO_KEY' end - local input = msg.text:input() - local caption = '' + local input = utilities.input(msg.text) local date = '*' local disable_page_preview = false - local url = 'https://api.nasa.gov/planetary/apod?api_key=' .. config.nasa_api_key + local url = 'https://api.nasa.gov/planetary/apod?api_key=' .. self.config.nasa_api_key if input then if input:match('(%d+)%-(%d+)%-(%d+)$') then url = url .. '&date=' .. URL.escape(input) date = date .. input else - sendMessage(msg.chat.id, doc, true, msg.message_id, true) + bindings.sendMessage(self, msg.chat.id, apod.doc, true, msg.message_id, true) return end else @@ -45,14 +51,14 @@ local action = function(msg) local jstr, res = HTTPS.request(url) if res ~= 200 then - sendReply(msg, config.errors.connection) + bindings.sendReply(self, msg, self.config.errors.connection) return end local jdat = JSON.decode(jstr) if jdat.error then - sendReply(msg, config.errors.results) + bindings.sendReply(msg, self.config.errors.results) return end @@ -62,7 +68,7 @@ local action = function(msg) img_url = jdat.hdurl or jdat.url end - output = date .. '[' .. jdat.title .. '](' .. img_url .. ')' + local output = date .. '[' .. jdat.title .. '](' .. img_url .. ')' if string.match(msg.text, '^/apodtext*') then output = output .. '\n' .. jdat.explanation @@ -73,13 +79,8 @@ local action = function(msg) output = output .. '\nCopyright: ' .. jdat.copyright end - sendMessage(msg.chat.id, output, disable_page_preview, nil, true) + bindings.sendMessage(self, msg.chat.id, output, disable_page_preview, nil, true) end -return { - action = action, - triggers = triggers, - doc = doc, - command = command -} +return apod diff --git a/plugins/bandersnatch.lua b/plugins/bandersnatch.lua index 5950ebe..0411494 100755 --- a/plugins/bandersnatch.lua +++ b/plugins/bandersnatch.lua @@ -1,13 +1,17 @@ -local command = 'bandersnatch' -local doc = [[``` +local bandersnatch = {} + +local bindings = require('bindings') +local utilities = require('utilities') + +bandersnatch.command = 'bandersnatch' +bandersnatch.doc = [[``` Shun the frumious Bandersnatch. Alias: /bc ```]] -local triggers = { - '^/bandersnatch[@'..bot.username..']*', - '^/bc[@'..bot.username..']*' -} +function bandersnatch:init() + bandersnatch.triggers = utilities.triggers(self.info.username):trigger('bandersnatch'):trigger('bc').table +end local fullnames = { "Wimbledon Tennismatch", "Rinkydink Curdlesnoot", "Butawhiteboy Cantbekhan", "Benadryl Claritin", "Bombadil Rivendell", "Wanda's Crotchfruit", "Biblical Concubine", "Syphilis Cankersore", "Buckminster Fullerene", "Bourgeoisie Capitalist" } @@ -15,7 +19,7 @@ local firstnames = { "Bumblebee", "Bandersnatch", "Broccoli", "Rinkydink", "Bomb local lastnames = { "Coddleswort", "Crumplesack", "Curdlesnoot", "Calldispatch", "Humperdinck", "Rivendell", "Cuttlefish", "Lingerie", "Vegemite", "Ampersand", "Cumberbund", "Candycrush", "Clombyclomp", "Cragglethatch", "Nottinghill", "Cabbagepatch", "Camouflage","Creamsicle", "Curdlemilk", "Upperclass", "Frumblesnatch", "Crumplehorn", "Talisman", "Candlestick", "Chesterfield", "Bumbersplat", "Scratchnsniff", "Snugglesnatch", "Charizard", "Carrotstick", "Cumbercooch", "Crackerjack", "Crucifix", "Cuckatoo", "Cockletit", "Collywog", "Capncrunch", "Covergirl", "Cumbersnatch", "Countryside","Coggleswort", "Splishnsplash", "Copperwire", "Animorph", "Curdledmilk", "Cheddarcheese", "Cottagecheese", "Crumplehorn", "Snickersbar", "Banglesnatch", "Stinkyrash", "Cameltoe", "Chickenbroth", "Concubine", "Candygram", "Moldyspore", "Chuckecheese", "Cankersore", "Crimpysnitch", "Wafflesmack", "Chowderpants", "Toodlesnoot", "Clavichord", "Cuckooclock", "Oxfordshire", "Cumbersome", "Chickenstrips", "Battleship", "Commonwealth", "Cunningsnatch", "Custardbath", "Kryptonite", "Curdlesnoot", "Cummerbund", "Coochyrash", "Crackerdong", "Crackerdong", "Curdledong", "Crackersprout", "Crumplebutt", "Colonist", "Coochierash", "Thundersnatch" } -local action = function(msg) +function bandersnatch:action(msg) local message @@ -25,13 +29,8 @@ local action = function(msg) message = firstnames[math.random(#firstnames)] .. ' ' .. lastnames[math.random(#lastnames)] end - sendReply(msg, message) + bindings.sendReply(self, msg, message) end -return { - action = action, - triggers = triggers, - command = command, - desc = desc -} +return bandersnatch diff --git a/plugins/bible.lua b/plugins/bible.lua index 03aca67..a556d48 100755 --- a/plugins/bible.lua +++ b/plugins/bible.lua @@ -1,54 +1,54 @@ -if not config.biblia_api_key then - print('Missing config value: biblia_api_key.') - print('bible.lua will not be enabled.') - return +local bible = {} + +local HTTP = require('socket.http') +local URL = require('socket.url') +local bindings = require('bindings') +local utilities = require('utilities') + +function bible:init() + if not self.config.biblia_api_key then + print('Missing config value: biblia_api_key.') + print('bible.lua will not be enabled.') + return + end + + bible.triggers = utilities.triggers(self.info.username):t('bible', true):t('b', true).table end -local command = 'bible ' -local doc = [[``` +bible.command = 'bible ' +bible.doc = [[``` /bible Returns a verse from the American Standard Version of the Bible, or an apocryphal verse from the King James Version. Results from biblia.com. Alias: /b ```]] -local triggers = { - '^/bible*[@'..bot.username..']*', - '^/b[@'..bot.username..']* ', - '^/b[@'..bot.username..']*$' -} +function bible:action(msg) -local action = function(msg) - - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then - sendMessage(msg.chat.id, doc, true, msg.message_id, true) + bindings.sendMessage(self, msg.chat.id, self.doc, true, msg.message_id, true) return end - local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input) + local url = 'http://api.biblia.com/v1/bible/content/ASV.txt?key=' .. self.config.biblia_api_key .. '&passage=' .. URL.escape(input) local message, res = HTTP.request(url) if not message or res ~= 200 or message:len() == 0 then - url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. config.biblia_api_key .. '&passage=' .. URL.escape(input) + url = 'http://api.biblia.com/v1/bible/content/KJVAPOC.txt?key=' .. self.config.biblia_api_key .. '&passage=' .. URL.escape(input) message, res = HTTP.request(url) end if not message or res ~= 200 or message:len() == 0 then - message = config.errors.results + message = self.config.errors.results end if message:len() > 4000 then message = 'The text is too long to post here. Try being more specific.' end - sendReply(msg, message) + bindings.sendReply(self, msg, message) end -return { - action = action, - triggers = triggers, - command = command, - doc = doc -} +return bible diff --git a/plugins/blacklist.lua b/plugins/blacklist.lua index 9af0ed5..4a77457 100755 --- a/plugins/blacklist.lua +++ b/plugins/blacklist.lua @@ -1,24 +1,31 @@ -- This plugin will allow the admin to blacklist users who will be unable to -- use the bot. This plugin should be at the top of your plugin list in config. -if not database.blacklist then - database.blacklist = {} +local blacklist = {} + +local bindings = require('bindings') +local utilities = require('utilities') + +function blacklist:init() + if not self.database.blacklist then + self.database.blacklist = {} + end end -local triggers = { +blacklist.triggers = { '' } - local action = function(msg) +function blacklist:action(msg) - if database.blacklist[msg.from.id_str] then return end - if database.blacklist[msg.chat.id_str] then return end + if self.database.blacklist[msg.from.id_str] then return end + if self.database.blacklist[msg.chat.id_str] then return end if not msg.text:match('^/blacklist') then return true end - if msg.from.id ~= config.admin then return end + if msg.from.id ~= self.config.admin then return end - local target = user_from_message(msg) + local target = utilities.user_from_message(self, msg) if target.err then - sendReply(msg, target.err) + bindings.sendReply(self, msg, target.err) return end @@ -26,17 +33,14 @@ local triggers = { target.name = 'Group' end - if database.blacklist[tostring(target.id)] then - database.blacklist[tostring(target.id)] = nil - sendReply(msg, target.name .. ' has been removed from the blacklist.') + if self.database.blacklist[tostring(target.id)] then + self.database.blacklist[tostring(target.id)] = nil + bindings.sendReply(self, msg, target.name .. ' has been removed from the blacklist.') else - database.blacklist[tostring(target.id)] = true - sendReply(msg, target.name .. ' has been added to the blacklist.') + self.database.blacklist[tostring(target.id)] = true + bindings.sendReply(self, msg, target.name .. ' has been added to the blacklist.') end end - return { - action = action, - triggers = triggers -} + return blacklist diff --git a/plugins/calc.lua b/plugins/calc.lua index 0d854d1..53a5bfd 100755 --- a/plugins/calc.lua +++ b/plugins/calc.lua @@ -1,21 +1,28 @@ -local command = 'calc ' -local doc = [[``` +local calc = {} + +local URL = require('socket.url') +local HTTPS = require('ssl.https') +local bindings = require('bindings') +local utilities = require('utilities') + +calc.command = 'calc ' +calc.doc = [[``` /calc Returns solutions to mathematical expressions and conversions between common units. Results provided by mathjs.org. ```]] -local triggers = { - '^/calc[@'..bot.username..']*' -} +function calc:init() + calc.triggers = utilities.triggers(self.info.username):t('calc', true).table +end -local action = function(msg) +function calc:action(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text else - sendMessage(msg.chat.id, doc, true, msg.message_id, true) + bindings.sendMessage(msg.chat.id, calc.doc, true, msg.message_id, true) return end end @@ -24,19 +31,14 @@ local action = function(msg) local output = HTTPS.request(url) if not output then - sendReply(msg, config.errors.connection) + bindings.sendReply(self, msg, self.config.errors.connection) return end output = '`' .. output .. '`' - sendMessage(msg.chat.id, output, true, msg.message_id, true) + bindings.sendMessage(self, msg.chat.id, output, true, msg.message_id, true) end -return { - action = action, - triggers = triggers, - command = command, - doc = doc -} +return calc diff --git a/plugins/cats.lua b/plugins/cats.lua index 53a15c6..d72f885 100755 --- a/plugins/cats.lua +++ b/plugins/cats.lua @@ -1,38 +1,39 @@ -if not config.thecatapi_key then - print('Missing config value: thecatapi_key.') - print('cats.lua will be enabled, but there are more features with a key.') +local cats = {} + +local HTTP = require('socket.http') +local bindings = require('bindings') +local utilities = require('utilities') + +function bindings:init() + if not self.config.thecatapi_key then + print('Missing config value: thecatapi_key.') + print('cats.lua will be enabled, but there are more features with a key.') + end end -local command = 'cat' -local doc = '`Returns a cat!`' +cats.command = 'cat' +cats.doc = '`Returns a cat!`' -local triggers = { - '^/cat[@'..bot.username..']*$' -} +cats.triggers = utilities.triggers():t('cat') -local action = function(msg) +function cats:action(msg) local url = 'http://thecatapi.com/api/images/get?format=html&type=jpg' - if config.thecatapi_key then - url = url .. '&api_key=' .. config.thecatapi_key + if self.config.thecatapi_key then + url = url .. '&api_key=' .. self.config.thecatapi_key end local str, res = HTTP.request(url) if res ~= 200 then - sendReply(msg, config.errors.connection) + bindings.sendReply(msg, self.config.errors.connection) return end str = str:match('') local output = '[Cat!]('..str..')' - sendMessage(msg.chat.id, output, false, nil, true) + bindings.sendMessage(self, msg.chat.id, output, false, nil, true) end -return { - action = action, - triggers = triggers, - doc = doc, - command = command -} +return cats diff --git a/plugins/dice.lua b/plugins/dice.lua index 7ae3345..0da32f5 100755 --- a/plugins/dice.lua +++ b/plugins/dice.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text_lower:input() + local input = utilities.input(msg.text_lower) if not input then sendMessage(msg.chat.id, doc, true, msg.message_id, true) return diff --git a/plugins/dilbert.lua b/plugins/dilbert.lua index 2511da0..5b53b70 100644 --- a/plugins/dilbert.lua +++ b/plugins/dilbert.lua @@ -16,7 +16,7 @@ local action = function(msg) sendChatAction(msg.chat.id, 'upload_photo') - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then input = os.date('%F') end if not input:match('^%d%d%d%d%-%d%d%-%d%d$') then input = os.date('%F') end diff --git a/plugins/echo.lua b/plugins/echo.lua index c52d78b..d0e5731 100755 --- a/plugins/echo.lua +++ b/plugins/echo.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then sendMessage(msg.chat.id, doc, true, msg.message_id, true) diff --git a/plugins/gImages.lua b/plugins/gImages.lua index f01c233..99c8c88 100755 --- a/plugins/gImages.lua +++ b/plugins/gImages.lua @@ -27,7 +27,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/gMaps.lua b/plugins/gMaps.lua index b2acc34..1b49d8c 100755 --- a/plugins/gMaps.lua +++ b/plugins/gMaps.lua @@ -13,7 +13,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/gSearch.lua b/plugins/gSearch.lua index 23f9c2b..bf906e9 100755 --- a/plugins/gSearch.lua +++ b/plugins/gSearch.lua @@ -14,7 +14,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/hearthstone.lua b/plugins/hearthstone.lua index 8370702..9de002d 100755 --- a/plugins/hearthstone.lua +++ b/plugins/hearthstone.lua @@ -96,7 +96,7 @@ end local action = function(msg) - local input = msg.text_lower:input() + local input = utilities.input(msg.text_lower) if not input then sendMessage(msg.chat.id, doc, true, msg.message_id, true) return diff --git a/plugins/help.lua b/plugins/help.lua index c0589dd..155689a 100755 --- a/plugins/help.lua +++ b/plugins/help.lua @@ -22,7 +22,7 @@ local triggers = { local action = function(msg) - local input = msg.text_lower:input() + local input = utilities.input(msg.text_lower) -- Attempts to send the help message via PM. -- If msg is from a group, it tells the group whether the PM was successful. diff --git a/plugins/imdb.lua b/plugins/imdb.lua index 45cb543..d5756b0 100755 --- a/plugins/imdb.lua +++ b/plugins/imdb.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/lastfm.lua b/plugins/lastfm.lua index ee07874..49f52fe 100755 --- a/plugins/lastfm.lua +++ b/plugins/lastfm.lua @@ -24,7 +24,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if string.match(msg.text, '^/lastfm') then sendMessage(msg.chat.id, doc, true, msg.message_id, true) diff --git a/plugins/librefm.lua b/plugins/librefm.lua index 32e0b97..ddd5d96 100644 --- a/plugins/librefm.lua +++ b/plugins/librefm.lua @@ -19,7 +19,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if string.match(msg.text, '^/librefm') then sendMessage(msg.chat.id, doc, true, msg.message_id, true) diff --git a/plugins/luarun.lua b/plugins/luarun.lua index a4cd585..e56a912 100644 --- a/plugins/luarun.lua +++ b/plugins/luarun.lua @@ -8,7 +8,7 @@ local action = function(msg) return end - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then sendReply(msg, 'Please enter a string to load.') return diff --git a/plugins/me.lua b/plugins/me.lua index 68ece71..9c7c62e 100644 --- a/plugins/me.lua +++ b/plugins/me.lua @@ -7,7 +7,7 @@ local action = function(msg) local target = database.users[msg.from.id_str] - if msg.from.id == config.admin and (msg.reply_to_message or msg.text:input()) then + if msg.from.id == config.admin and (msg.reply_to_message or utilities.input(msg.text)) then target = user_from_message(msg) if target.err then sendReply(msg, target.err) diff --git a/plugins/moderation.lua b/plugins/moderation.lua index c8be00b..182f5b4 100755 --- a/plugins/moderation.lua +++ b/plugins/moderation.lua @@ -59,7 +59,7 @@ local commands = { ['^/modcast[@'..bot.username..']*'] = function(msg) - local output = msg.text:input() + local output = utilities.input(msg.text) if not output then return 'You must include a message.' end @@ -149,7 +149,7 @@ local commands = { return config.moderation.errors.not_admin end - local modid = msg.text:input() + local modid = utilities.input(msg.text) if not modid then if msg.reply_to_message then @@ -184,7 +184,7 @@ local commands = { end end - local userid = msg.text:input() + local userid = utilities.input(msg.text) local usernm = userid if msg.reply_to_message then @@ -216,7 +216,7 @@ local commands = { end end - local userid = msg.text:input() + local userid = utilities.input(msg.text) local usernm = userid if msg.reply_to_message then diff --git a/plugins/nick.lua b/plugins/nick.lua index d8b97a1..74b6b71 100755 --- a/plugins/nick.lua +++ b/plugins/nick.lua @@ -22,7 +22,7 @@ local action = function(msg) end local output - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if database.users[target.id_str].nickname then output = target.name .. '\'s nickname is "' .. database.users[target.id_str].nickname .. '".' diff --git a/plugins/pokedex.lua b/plugins/pokedex.lua index 2a7e57a..1b06c9b 100755 --- a/plugins/pokedex.lua +++ b/plugins/pokedex.lua @@ -12,7 +12,7 @@ local triggers = { local action = function(msg) - local input = msg.text_lower:input() + local input = utilities.input(msg.text_lower) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/preview.lua b/plugins/preview.lua index 234a7bd..8ba335c 100644 --- a/plugins/preview.lua +++ b/plugins/preview.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then sendMessage(msg.chat.id, doc, true, nil, true) diff --git a/plugins/reddit.lua b/plugins/reddit.lua index 7d8a16e..037a14c 100755 --- a/plugins/reddit.lua +++ b/plugins/reddit.lua @@ -15,12 +15,12 @@ local triggers = { local action = function(msg) msg.text_lower = msg.text_lower:gsub('/r/', '/r r/') - local input = msg.text_lower:input() + local input = utilities.input(msg.text_lower) if msg.text_lower:match('^/r/') then msg.text_lower = msg.text_lower:gsub('/r/', '/r r/') input = get_word(msg.text_lower, 1) else - input = msg.text_lower:input() + input = utilities.input(msg.text_lower) end local url diff --git a/plugins/setandget.lua b/plugins/setandget.lua index 79245cf..b34b52a 100644 --- a/plugins/setandget.lua +++ b/plugins/setandget.lua @@ -15,7 +15,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) database.setandget[msg.chat.id_str] = database.setandget[msg.chat.id_str] or {} if msg.text_lower:match('^/set') then @@ -26,7 +26,7 @@ local action = function(msg) end local name = get_word(input:lower(), 1) - local value = input:input() + local value = utilities.input(input) if not name or not value then sendMessage(msg.chat.id, doc, true, nil, true) diff --git a/plugins/shell.lua b/plugins/shell.lua index 5c218aa..1622d08 100644 --- a/plugins/shell.lua +++ b/plugins/shell.lua @@ -8,7 +8,7 @@ local action = function(msg) return end - local input = msg.text:input() + local input = utilities.input(msg.text) input = input:gsub('—', '--') if not input then diff --git a/plugins/shout.lua b/plugins/shout.lua index 24c2f3e..873d7ac 100644 --- a/plugins/shout.lua +++ b/plugins/shout.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then sendMessage(msg.chat.id, doc, true, msg.message_id, true) diff --git a/plugins/slap.lua b/plugins/slap.lua index 3e9c894..819df66 100755 --- a/plugins/slap.lua +++ b/plugins/slap.lua @@ -94,7 +94,7 @@ local slaps = { local action = function(msg) - local victim = msg.text:input() + local victim = utilities.input(msg.text) if msg.reply_to_message then if database.users[tostring(msg.reply_to_message.from.id)].nickname then victim = database.users[tostring(msg.reply_to_message.from.id)].nickname diff --git a/plugins/time.lua b/plugins/time.lua index 1accc2e..05c7c2b 100755 --- a/plugins/time.lua +++ b/plugins/time.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/translate.lua b/plugins/translate.lua index b955be6..2be913b 100755 --- a/plugins/translate.lua +++ b/plugins/translate.lua @@ -11,7 +11,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/urbandictionary.lua b/plugins/urbandictionary.lua index 9cbef94..9b2f94d 100755 --- a/plugins/urbandictionary.lua +++ b/plugins/urbandictionary.lua @@ -14,7 +14,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/weather.lua b/plugins/weather.lua index 3f42618..8199624 100755 --- a/plugins/weather.lua +++ b/plugins/weather.lua @@ -16,7 +16,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/wikipedia.lua b/plugins/wikipedia.lua index 4d94f57..4dfd882 100755 --- a/plugins/wikipedia.lua +++ b/plugins/wikipedia.lua @@ -14,7 +14,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/plugins/xkcd.lua b/plugins/xkcd.lua index 9e4ac97..a8c0903 100755 --- a/plugins/xkcd.lua +++ b/plugins/xkcd.lua @@ -10,7 +10,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) local jstr, res = HTTP.request('http://xkcd.com/info.0.json') if res ~= 200 then diff --git a/plugins/youtube.lua b/plugins/youtube.lua index b1e6b10..0bbbe49 100755 --- a/plugins/youtube.lua +++ b/plugins/youtube.lua @@ -21,7 +21,7 @@ local triggers = { local action = function(msg) - local input = msg.text:input() + local input = utilities.input(msg.text) if not input then if msg.reply_to_message and msg.reply_to_message.text then input = msg.reply_to_message.text diff --git a/utilities.lua b/utilities.lua index 2e5fe94..8527602 100755 --- a/utilities.lua +++ b/utilities.lua @@ -1,13 +1,17 @@ -- utilities.lua -- Functions shared among plugins. - -- you're welcome, brayden :^) -HTTP = HTTP or require('socket.http') -HTTPS = HTTPS or require('ssl.https') -JSON = JSON or require('cjson') +local utilities = {} + +local HTTP = require('socket.http') +local ltn12 = require('ltn12') +local HTTPS = require('ssl.https') +local URL = require('socket.url') +local JSON = require('cjson') +local bindings = require('bindings') -- get the indexed word in a string -get_word = function(s, i) +function utilities.get_word(s, i) s = s or '' i = i or 1 @@ -23,7 +27,7 @@ end -- Like get_word(), but better. -- Returns the actual index. -function string:index() +function utilities.index(s) local t = {} for w in s:gmatch('%g+') do table.insert(t, w) @@ -32,16 +36,16 @@ function string:index() end -- Returns the string after the first space. -function string:input() - if not self:find(' ') then +function utilities.input(s) + if not s:find(' ') then return false end - return self:sub(self:find(' ')+1) + return s:sub(s:find(' ')+1) end -- I swear, I copied this from PIL, not yago! :) -function string:trim() -- Trims whitespace from a string. - local s = self:gsub('^%s*(.-)%s*$', '%1') +function utilities.trim(str) -- Trims whitespace from a string. + local s = str:gsub('^%s*(.-)%s*$', '%1') return s end @@ -75,7 +79,7 @@ local lc_list = { } -- Replaces letters with corresponding Cyrillic characters. -latcyr = function(str) +function utilities.latcyr(str) for k,v in pairs(lc_list) do str = str:gsub(k, v) end @@ -83,7 +87,7 @@ latcyr = function(str) end -- Loads a JSON file as a table. -load_data = function(filename) +function utilities.load_data(filename) local f = io.open(filename) if not f then @@ -98,7 +102,7 @@ load_data = function(filename) end -- Saves a table to a JSON file. -save_data = function(filename, data) +function utilities.save_data(filename, data) local s = JSON.encode(data) local f = io.open(filename, 'w') @@ -108,18 +112,18 @@ save_data = function(filename, data) end -- Gets coordinates for a location. Used by gMaps.lua, time.lua, weather.lua. -get_coords = function(input) +function utilities:get_coords(input) local url = 'http://maps.googleapis.com/maps/api/geocode/json?address=' .. URL.escape(input) local jstr, res = HTTP.request(url) if res ~= 200 then - return config.errors.connection + return self.config.errors.connection end local jdat = JSON.decode(jstr) if jdat.status == 'ZERO_RESULTS' then - return config.errors.results + return self.config.errors.results end return { @@ -130,10 +134,10 @@ get_coords = function(input) end -- Get the number of values in a key/value table. -table_size = function(tab) +function utilities.table_size(tab) local i = 0 - for k,v in pairs(tab) do + for _,_ in pairs(tab) do i = i + 1 end return i @@ -141,7 +145,7 @@ table_size = function(tab) end -- Just an easy way to get a user's full name. -build_name = function(first, last) +function utilities.build_name(first, last) if last then return first .. ' ' .. last else @@ -149,10 +153,10 @@ build_name = function(first, last) end end -resolve_username = function(input) +function utilities:resolve_username(input) input = input:gsub('^@', '') - for k,v in pairs(database.users) do + for _,v in pairs(self.database.users) do if v.username and v.username:lower() == input:lower() then return v end @@ -160,22 +164,22 @@ resolve_username = function(input) end -user_from_message = function(msg) +function utilities:user_from_message(msg) - local input = msg.text_lower:input() + local input = utilities.input(msg.text_lower) local target = {} if msg.reply_to_message then target = msg.reply_to_message.from elseif input and tonumber(input) then target.id = input - if database.users[input] then - for k,v in pairs(database.users[input]) do + if self.database.users[input] then + for k,v in pairs(self.database.users[input]) do target[k] = v end end elseif input and input:match('^@') then local uname = input:gsub('^@', '') - for k,v in pairs(database.users) do + for _,v in pairs(self.database.users) do if v.username and uname == v.username:lower() then for key, val in pairs(v) do target[key] = val @@ -195,21 +199,21 @@ user_from_message = function(msg) if not target.first_name then target.first_name = 'User' end - target.name = build_name(target.first_name, target.last_name) + target.name = utilities.build_name(target.first_name, target.last_name) return target end -handle_exception = function(err, message) +function utilities:handle_exception(err, message) if not err then err = '' end - local output = '\n[' .. os.date('%F %T', os.time()) .. ']\n' .. bot.username .. ': ' .. err .. '\n' .. message .. '\n' + local output = '\n[' .. os.date('%F %T', os.time()) .. ']\n' .. self.info.username .. ': ' .. err .. '\n' .. message .. '\n' - if config.log_chat then + if self.config.log_chat then output = '```' .. output .. '```' - sendMessage(config.log_chat, output, true, nil, true) + bindings.sendMessage(self, self.config.log_chat, output, true, nil, true) else print(output) end @@ -218,7 +222,7 @@ end -- Okay, this one I actually did copy from yagop. -- https://github.com/yagop/telegram-bot/blob/master/bot/utils.lua -download_file = function(url, filename) +function utilities.download_file(url, filename) local respbody = {} local options = { @@ -227,7 +231,7 @@ download_file = function(url, filename) redirect = true } - local response = nil + local response if url:match('^https') then options.redirect = false @@ -252,7 +256,7 @@ download_file = function(url, filename) end -markdown_escape = function(text) +function utilities.markdown_escape(text) text = text:gsub('_', '\\_') text = text:gsub('%[', '\\[') @@ -262,11 +266,30 @@ markdown_escape = function(text) end -function string:md_escape() - local text = self - text = text:gsub('_', '\\_') - text = text:gsub('%[', '\\[') - text = text:gsub('%*', '\\*') - text = text:gsub('`', '\\`') - return text +function utilities.md_escape(s) + s = s:gsub('_', '\\_') + s = s:gsub('%[', '\\[') + s = s:gsub('%*', '\\*') + s = s:gsub('`', '\\`') + return s +end + +utilities.INVOCATION_PATTERN = '/' + +utilities.triggers_metatable = {} +function utilities.triggers_metatable:t(pattern, has_args) + self.table:insert('^'..utilities.INVOCATION_PATTERN..pattern..'$') + self.table:insert('^'..utilities.INVOCATION_PATTERN..pattern..'@'..self.username..'$') + if has_args then + self.table:insert('^'..utilities.INVOCATION_PATTERN..pattern..'%s+[^%s]*') + self.table:insert('^'..utilities.INVOCATION_PATTERN..pattern..'@'..self.username..'%s+[^%s]*') + end + return self +end + +function utilities.triggers(username) + local self = setmetatable({}, utilities.triggers_metatable) + self.username = username + self.table = {} + return self end