diff --git a/otouto/bot.lua b/otouto/bot.lua index 2f1952e..71b8071 100644 --- a/otouto/bot.lua +++ b/otouto/bot.lua @@ -80,8 +80,9 @@ function bot:on_msg_receive(msg, config) -- The fn run whenever a message is rec msg = pre_process_msg(self, msg, config) - match_plugins(self, msg, config) - + for _, plugin in ipairs(self.plugins) do + match_plugins(self, msg, config, plugin) + end end function bot:run(config) @@ -132,43 +133,41 @@ function pre_process_msg(self, msg, config) return new_msg end -function match_plugins(self, msg, config) - for _, plugin in ipairs(self.plugins) do - for _, trigger in pairs(plugin.triggers) do - if string.match(msg.text_lower, trigger) then - -- Check if Plugin is disabled - if is_plugin_disabled_on_chat(plugin.name, msg) then return end - local success, result = pcall(function() - -- trying to port matches to otouto - for k, pattern in pairs(plugin.triggers) do - matches = match_pattern(pattern, msg.text) - if matches then - break; - end +function match_plugins(self, msg, config, plugin) + for _, trigger in pairs(plugin.triggers) do + if string.match(msg.text_lower, trigger) then + -- Check if Plugin is disabled + if is_plugin_disabled_on_chat(plugin.name, msg) then return end + local success, result = pcall(function() + -- trying to port matches to otouto + for k, pattern in pairs(plugin.triggers) do + matches = match_pattern(pattern, msg.text) + if matches then + break; end - return plugin.action(self, msg, config, matches) - end) - if not success then - -- If the plugin has an error message, send it. If it does - -- not, use the generic one specified in config. If it's set - -- to false, do nothing. - if plugin.error then - utilities.send_reply(self, msg, plugin.error) - elseif plugin.error == nil then - utilities.send_reply(self, msg, config.errors.generic, true) - end - utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config) + end + return plugin.action(self, msg, config, matches) + end) + if not success then + -- If the plugin has an error message, send it. If it does + -- not, use the generic one specified in config. If it's set + -- to false, do nothing. + if plugin.error then + utilities.send_reply(self, msg, plugin.error) + elseif plugin.error == nil then + utilities.send_reply(self, msg, config.errors.generic, true) + end + utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config) + return + end + -- If the action returns a table, make that table the new msg. + if type(result) == 'table' then + msg = result + -- If the action returns true, continue. + elseif result ~= true then return end - -- If the action returns a table, make that table the new msg. - if type(result) == 'table' then - msg = result - -- If the action returns true, continue. - elseif result ~= true then - return - end - end - end + end end end diff --git a/otouto/plugins/pocket.lua b/otouto/plugins/pocket.lua new file mode 100644 index 0000000..b974d09 --- /dev/null +++ b/otouto/plugins/pocket.lua @@ -0,0 +1,145 @@ +local pocket = {} + +local https = require('ssl.https') +local URL = require('socket.url') +local redis = (loadfile "./otouto/redis.lua")() +local utilities = require('otouto.utilities') +local bindings = require('otouto.bindings') + +function pocket:init(config) + if not cred_data.pocket_consumer_key then + print('Missing config value: pocket_consumer_key.') + print('pocket.lua will not be enabled.') + return + end + + pocket.triggers = { + "^/pocket (set) (.+)$", + "^/pocket (add) (https?://.*)$", + "^/pocket (archive) (%d+)$", + "^/pocket (readd) (%d+)$", + "^/pocket (unfavorite) (%d+)$", + "^/pocket (favorite) (%d+)$", + "^/pocket (delete) (%d+)$", + "^/pocket (unauth)$", + "^/pocket$" + } + + pocket.doc = [[* +]]..config.cmd_pat..[[pocket*: Postet Liste deiner Links +*]]..config.cmd_pat..[[pocket* add _(url)_: Fügt diese URL deiner Liste hinzu +*]]..config.cmd_pat..[[pocket* archive _[id]_: Archiviere diesen Eintrag +*]]..config.cmd_pat..[[pocket* readd _[id]_: De-archiviere diesen Eintrag +*]]..config.cmd_pat..[[pocket* favorite _[id]_: Favorisiere diesen Eintrag +*]]..config.cmd_pat..[[pocket* unfavorite _[id]_: Entfavorisiere diesen Eintrag +*]]..config.cmd_pat..[[pocket* delete _[id]_: Lösche diesen Eintrag +*]]..config.cmd_pat..[[pocket* unauth: Löscht deinen Account aus dem Bot]] +end + +pocket.command = 'pocket ' + +local BASE_URL = 'https://getpocket.com/v3' +local consumer_key = cred_data.pocket_consumer_key +local headers = { + ["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF8", + ["X-Accept"] = "application/json" +} + +function pocket:set_pocket_access_token(hash, access_token) + if string.len(access_token) ~= 30 then return '*Inkorrekter Access-Token*' end + print('Setting pocket in redis hash '..hash..' to users access_token') + redis:hset(hash, 'pocket', access_token) + return '*Authentifizierung abgeschlossen!*\nDas Plugin kann jetzt verwendet werden.' +end + +function pocket:list_pocket_items(access_token) + local items = post_petition(BASE_URL..'/get', 'consumer_key='..consumer_key..'&access_token='..access_token..'&state=unread&sort=newest&detailType=simple', headers) + + if items.status == 2 then return 'Keine Elemente eingespeichert.' end + if items.status ~= 1 then return 'Ein Fehler beim Holen der Elemente ist aufgetreten.' end + + local text = '' + for element in pairs(items.list) do + title = items.list[element].given_title + if not title or title == "" then title = items.list[element].resolved_title end + text = text..'#'..items.list[element].item_id..': '..title..'\n— '..items.list[element].resolved_url..'\n\n' + end + + return text +end + +function pocket:add_pocket_item(access_token, url) + local result = post_petition(BASE_URL..'/add', 'consumer_key='..consumer_key..'&access_token='..access_token..'&url='..url, headers) + if result.status ~= 1 then return 'Ein Fehler beim Hinzufügen der URL ist aufgetreten :(' end + local given_url = result.item.given_url + if result.item.title == "" then + title = 'Seite' + else + title = '"'..result.item.title..'"' + end + local code = result.item.response_code + + local text = title..' ('..given_url..') hinzugefügt!' + if code ~= "200" and code ~= "0" then text = text..'\nAber die Seite liefert Fehler '..code..' zurück.' end + return text +end + +function pocket:modify_pocket_item(access_token, action, id) + local result = post_petition(BASE_URL..'/send', 'consumer_key='..consumer_key..'&access_token='..access_token..'&actions=[{"action":"'..action..'","item_id":'..id..'}]', headers) + if result.status ~= 1 then return 'Ein Fehler ist aufgetreten :(' end + + if action == 'readd' then + if result.action_results[1] == false then + return 'Dieser Eintrag existiert nicht!' + end + local url = result.action_results[1].normal_url + return url..' wieder de-archiviert' + end + if result.action_results[1] == true then + return 'Aktion ausgeführt.' + else + return 'Ein Fehler ist aufgetreten.' + end +end + +function pocket:action(msg, config, matches) + local hash = 'user:'..msg.from.id + local access_token = redis:hget(hash, 'pocket') + + if matches[1] == 'set' then + local access_token = matches[2] + utilities.send_reply(self, msg, pocket:set_pocket_access_token(hash, access_token), true) + return + end + + if not access_token then + utilities.send_reply(self, msg, 'Bitte authentifiziere dich zuerst, indem du dich anmeldest:\n[Bei Pocket anmelden](https://brawlbot.tk/apis/callback/pocket/connect.php)', true) + return + end + + if matches[1] == 'unauth' then + redis:hdel(hash, 'pocket') + utilities.send_reply(self, msg, 'Erfolgreich ausgeloggt! Du kannst den Zugriff [in deinen Einstellungen](https://getpocket.com/connected_applications) endgültig entziehen.', true) + return + end + + if matches[1] == 'add' then + utilities.send_reply(self, msg, pocket:add_pocket_item(access_token, matches[2])) + return + end + + if matches[1] == 'archive' or matches[1] == 'delete' or matches[1] == 'readd' or matches[1] == 'favorite' or matches[1] == 'unfavorite' then + utilities.send_reply(self, msg, pocket:modify_pocket_item(access_token, matches[1], matches[2])) + return + end + + if msg.chat.type == 'chat' or msg.chat.type == 'supergroup' then + utilities.send_reply(self, msg, 'Ausgeben deiner privaten Pocket-Liste in einem öffentlichen Chat wird feige verweigert. Bitte schreibe mich privat an!', true) + return + else + utilities.send_reply(self, msg, pocket:list_pocket_items(access_token)) + return + end +end + +return pocket \ No newline at end of file diff --git a/otouto/utilities.lua b/otouto/utilities.lua index 4785794..d984ca4 100644 --- a/otouto/utilities.lua +++ b/otouto/utilities.lua @@ -9,7 +9,6 @@ local HTTPS = require('ssl.https') local URL = require('socket.url') local JSON = require('dkjson') local http = require('socket.http') -local https = require('ssl.https') local serpent = require("serpent") local bindings = require('otouto.bindings') local redis = (loadfile "./otouto/redis.lua")() @@ -250,74 +249,34 @@ function string.starts(String, Start) return Start == string.sub(String,1,string.len(Start)) end -function get_http_file_name(url, headers) - -- Eg: fooo.var - local file_name = url:match("[^%w]+([%.%w]+)$") - -- Any delimited aphanumeric on the url - file_name = file_name or url:match("[^%w]+(%w+)[^%w]+$") - -- Random name, hope content-type works - file_name = file_name or str:random(5) - - local content_type = headers["content-type"] - - local extension = nil - if content_type then - extension = mimetype.get_mime_extension(content_type) - end - - if extension then - file_name = file_name.."."..extension - end - - local disposition = headers["content-disposition"] - if disposition then - -- attachment; filename=CodeCogsEqn.png - file_name = disposition:match('filename=([^;]+)') or file_name - file_name = string.gsub(file_name, "\"", "") - end - - return file_name -end - -- Saves file to $HOME/tmp/. If file_name isn't provided, -- will get the text after the last "/" for filename -- and content-type for extension function download_to_file(url, file_name) - print("url to download: "..url) - - local respbody = {} - local options = { - url = url, - sink = ltn12.sink.table(respbody), - redirect = true - } - - -- nil, code, headers, status - local response = nil - - if string.starts(url, 'https') then - options.redirect = false - response = {HTTPS.request(options)} - else - response = {HTTP.request(options)} - end - - local code = response[2] - local headers = response[3] - local status = response[4] - - if code ~= 200 then return nil end - - file_name = file_name or get_http_file_name(url, headers) - - local file_path = "/home/anditest/tmp/telegram-bot/"..file_name - print("Saved to: "..file_path) - - file = io.open(file_path, "w+") - file:write(table.concat(respbody)) - file:close() - - return file_path + print('url to download: '..url) + if not file_name then + file_name = '/tmp/' .. url:match('.+/(.-)$') or '/tmp/' .. os.time() + else + file_name = '/tmp/' .. file_name + end + local body = {} + local doer = HTTP + local do_redir = true + if url:match('^https') then + doer = HTTPS + do_redir = false + end + local _, res = doer.request{ + url = url, + sink = ltn12.sink.table(body), + redirect = do_redir + } + if res ~= 200 then return false end + local file = io.open(file_name, 'w+') + file:write(table.concat(body)) + file:close() + print('Saved to: '..file_name) + return file_name end function vardump(value) @@ -462,28 +421,9 @@ function utilities:handle_exception(err, message, config) end +-- MOVED TO DOWNLOAD_TO_FILE function utilities.download_file(url, filename) - if not filename then - filename = url:match('.+/(.-)$') or os.time() - filename = '/tmp/' .. filename - end - local body = {} - local doer = HTTP - local do_redir = true - if url:match('^https') then - doer = HTTPS - do_redir = false - end - local _, res = doer.request{ - url = url, - sink = ltn12.sink.table(body), - redirect = do_redir - } - if res ~= 200 then return false end - local file = io.open(filename, 'w+') - file:write(table.concat(body)) - file:close() - return filename + return download_to_file(url, filename) end function utilities.markdown_escape(text) @@ -674,7 +614,7 @@ function post_petition(url, arguments, headers) if post_prot == "http" then ok, response_code, response_headers, response_status_line = http.request(request_constructor) else - ok, response_code, response_headers, response_status_line = https.request(request_constructor) + ok, response_code, response_headers, response_status_line = HTTPS.request(request_constructor) end if not ok then