This repository has been archived on 2021-04-24. You can view files and clone it, but cannot push or open issues or pull requests.
Mikubot-2/otouto/plugins/github_feed.lua
2016-09-08 01:35:10 +02:00

299 lines
9.2 KiB
Lua

local gh_feed = {}
gh_feed.command = 'gh <sub/del>'
function gh_feed:init(config)
if not cred_data.github_token then
print('Missing config value: github_token.')
print('github_feed.lua will not be enabled.')
return
elseif not cred_data.github_username then
print('Missing config value: github_username.')
print('github_feed.lua will not be enabled.')
return
end
gh_feed.triggers = {
"^/(gh) @(.*)$",
"^/gh$",
"^/gh (sub) ([A-Za-z0-9-_-.-._.]+/[A-Za-z0-9-_-.-._.]+) @(.*)$",
"^/gh (sub) ([A-Za-z0-9-_-.-._.]+/[A-Za-z0-9-_-.-._.]+)$",
"^/gh (del) (%d+) @(.*)$",
"^/gh (del) (%d+)$",
"^/gh (del)",
"^/gh (sync)$"
}
gh_feed.doc = [[*
]]..config.cmd_pat..[[gh* _@[Kanalname]_: GitHub-Abonnements anzeigen
*]]..config.cmd_pat..[[gh* _sub_ _<URL>_ _@[Kanalname]_: Diese Repo abonnieren
*]]..config.cmd_pat..[[gh* _del_ _<#>_ _@[Kanalname]_: Diese Repo deabonnieren
*]]..config.cmd_pat..[[gh* _sync_: Repos syncen (nur Superuser)
Der Kanalname ist optional]]
end
local token = cred_data.github_token -- get a token here: https://github.com/settings/tokens/new (you don't need any scopes)
local BASE_URL = 'https://api.github.com/repos'
function gh_feed_get_base_redis(id, option, extra)
local ex = ''
if option ~= nil then
ex = ex .. ':' .. option
if extra ~= nil then
ex = ex .. ':' .. extra
end
end
return 'github:' .. id .. ex
end
function gh_feed_check_modified(repo, cur_etag, last_date)
local url = BASE_URL..'/'..repo
local response_body = {}
local request_constructor = {
url = url,
method = "HEAD",
redirect = false,
headers = {
Authorization = 'token '..token,
["If-None-Match"] = cur_etag
}
}
local ok, response_code = https.request(request_constructor)
if not ok then return nil end
if response_code == 304 then return true end
local url = BASE_URL..'/'..repo..'/commits?since='..last_date
local response_body = {}
local request_constructor = {
url = url,
method = "GET",
sink = ltn12.sink.table(response_body),
headers = {
Authorization = 'token '..token
}
}
local ok, response_code, response_headers = https.request(request_constructor)
if not response_headers then return nil end
local data = json.decode(table.concat(response_body))
return false, data, response_headers.etag
end
function gh_feed:check_repo(repo)
local url = BASE_URL..'/'..repo
local response_body = {}
local request_constructor = {
url = url,
method = "GET",
sink = ltn12.sink.table(response_body),
headers = {
Authorization = 'token '..token
}
}
local ok, response_code, response_headers = https.request(request_constructor)
if not ok then return nil end
return json.decode(table.concat(response_body)), response_headers.etag
end
function gh_feed:subscribe(id, repo)
local lasthash = gh_feed_get_base_redis(repo, "last_commit")
local lastetag = gh_feed_get_base_redis(repo, "etag")
local lastdate = gh_feed_get_base_redis(repo, "date")
local lhash = gh_feed_get_base_redis(repo, "subs")
local uhash = gh_feed_get_base_redis(id)
if redis:sismember(uhash, repo) then
return "Du hast `"..repo.."` bereits abonniert."
end
local data, etag = gh_feed:check_repo(repo)
if not data or not data.full_name then return 'Diese Repo gibt es nicht!' end
if not etag then return 'Ein Fehler ist aufgetreten.' end
local last_commit = ""
local pushed_at = data.pushed_at
local name = data.full_name
redis:set(lasthash, last_commit)
redis:set(lastdate, pushed_at)
redis:set(lastetag, etag)
redis:sadd(lhash, id)
redis:sadd(uhash, repo)
return "_"..utilities.md_escape(name) .."_ abonniert!"
end
function gh_feed:unsubscribe(id, n)
if #n > 3 then
return "Du kannst nicht mehr als drei Repos abonnieren!"
end
n = tonumber(n)
local uhash = gh_feed_get_base_redis(id)
local subs = redis:smembers(uhash)
if n < 1 or n > #subs then
return "Abonnement-ID zu hoch!"
end
local sub = subs[n]
local lhash = gh_feed_get_base_redis(sub, "subs")
redis:srem(uhash, sub)
redis:srem(lhash, id)
local left = redis:smembers(lhash)
if #left < 1 then -- no one subscribed, remove it
local lastetag = gh_feed_get_base_redis(sub, "etag")
local lastdate = gh_feed_get_base_redis(sub, "date")
local lasthash = gh_feed_get_base_redis(sub, "last_commit")
redis:del(lastetag)
redis:del(lasthash)
redis:del(lastdate)
end
return "Du hast `"..utilities.md_escape(sub).."` deabonniert."
end
function gh_feed:print_subs(id, chat_name)
local uhash = gh_feed_get_base_redis(id)
local subs = redis:smembers(uhash)
if not subs[1] then
return 'Keine GitHub-Repos abonniert!'
end
local keyboard = '{"keyboard":[['
local keyboard_buttons = ''
local text = '*'..chat_name..'* hat abonniert:\n---------\n'
for k,v in pairs(subs) do
text = text .. k .. ") ["..v.."](https://github.com/"..v..')\n'
if k == #subs then
keyboard_buttons = keyboard_buttons..'{"text":"/gh del '..k..'"}'
break;
end
keyboard_buttons = keyboard_buttons..'{"text":"/gh del '..k..'"},'
end
local keyboard = keyboard..keyboard_buttons..']], "one_time_keyboard":true, "selective":true, "resize_keyboard":true}'
return text, keyboard
end
function gh_feed:action(msg, config, matches)
local id = msg.from.id
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
id = msg.chat.id
end
-- For channels
if matches[1] == 'sub' and matches[2] and matches[3] then
if not is_sudo(msg, config) then
utilities.send_reply(msg, config.errors.sudo)
return
end
local id = '@'..matches[3]
local result = utilities.get_chat_info(id)
if not result then
utilities.send_reply(msg, 'Diesen Kanal gibt es nicht!')
return
end
local output = gh_feed:subscribe(id, matches[2])
utilities.send_reply(msg, output, true)
return
elseif matches[1] == 'del' and matches[2] and matches[3] then
if not is_sudo(msg, config) then
utilities.send_reply(msg, config.errors.sudo)
return
end
local id = '@'..matches[3]
local result = utilities.get_chat_info(id)
if not result then
utilities.send_reply(msg, 'Diesen Kanal gibt es nicht!')
return
end
local output = gh_feed:unsubscribe(id, matches[2])
utilities.send_reply(msg, output, true)
return
elseif matches[1] == 'gh' and matches[2] then
local id = '@'..matches[2]
local result = utilities.get_chat_info(id)
if not result then
utilities.send_reply(msg, 'Diesen Kanal gibt es nicht!')
return
end
local chat_name = result.result.title
local output = gh_feed:print_subs(id, chat_name)
utilities.send_reply(msg, output, true)
return
end
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
chat_name = msg.chat.title
else
chat_name = msg.chat.first_name
end
if matches[1] == 'sub' and matches[2] then
if not is_sudo(msg, config) then
utilities.send_reply(msg, config.errors.sudo)
return
end
local output = gh_feed:subscribe(id, matches[2])
utilities.send_reply(msg, output, true)
return
elseif matches[1] == 'del' and matches[2] then
if not is_sudo(msg, config) then
utilities.send_reply(msg, config.errors.sudo)
return
end
local output = gh_feed:unsubscribe(id, matches[2])
utilities.send_reply(msg, output, true, '{"hide_keyboard":true}')
return
elseif matches[1] == 'del' and not matches[2] then
local list_subs, keyboard = gh_feed:print_subs(id, chat_name)
utilities.send_reply(msg, list_subs, true, keyboard)
return
elseif matches[1] == 'sync' then
if not is_sudo(msg, config) then
utilities.send_reply(msg, config.errors.sudo)
return
end
gh_feed:cron()
return
end
local output = gh_feed:print_subs(id, chat_name)
utilities.send_reply(msg, output, true)
return
end
function gh_feed:cron()
local keys = redis:keys(gh_feed_get_base_redis("*", "subs"))
for k,v in pairs(keys) do
local repo = string.match(v, "github:(.+):subs")
print('GitHub: '..repo)
local cur_etag = redis:get(gh_feed_get_base_redis(repo, "etag"))
local last_date = redis:get(gh_feed_get_base_redis(repo, "date"))
local was_not_modified, data, last_etag = gh_feed_check_modified(repo, cur_etag, last_date)
if not was_not_modified then
if not data or not last_etag then return end
-- When there are new commits
local last_commit = redis:get(gh_feed_get_base_redis(repo, "last_commit"))
text = ''
for n in ipairs(data) do
if data[n].sha ~= last_commit then
local sha = data[n].sha
local author = data[n].commit.author.name
local message = utilities.md_escape(data[n].commit.message)
local link = data[n].html_url
text = text..'\n#GitHub: `'..repo..'@'..sha..'` von *'..author..'*:\n'..message..'\n[GitHub aufrufen]('..link..')\n'
end
end
if text ~= '' then
local last_commit = data[1].sha
local last_date = data[1].commit.author.date
redis:set(gh_feed_get_base_redis(repo, "last_commit"), last_commit)
redis:set(gh_feed_get_base_redis(repo, "etag"), last_etag)
redis:set(gh_feed_get_base_redis(repo, "date"), last_date)
for k2, receiver in pairs(redis:smembers(v)) do
utilities.send_message(receiver, text, true, nil, true)
end
end
end
end
end
return gh_feed