Initial
This commit is contained in:
commit
05a8e9b0ae
1 changed files with 139 additions and 0 deletions
139
mod_slack_webhooks.lua
Normal file
139
mod_slack_webhooks.lua
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
-- Allow Slack-style incoming and outgoing hooks to MUC rooms
|
||||||
|
-- Based on mod_muc_intercom and mod_post_msg
|
||||||
|
-- Copyright 2016-2017 Nathan Whitehorn <nwhitehorn@physics.ucla.edu>
|
||||||
|
--
|
||||||
|
-- This file is MIT/X11 licensed.
|
||||||
|
|
||||||
|
module:depends"http"
|
||||||
|
|
||||||
|
local msg = require "util.stanza".message;
|
||||||
|
local jid = require "util.jid";
|
||||||
|
local now = require "util.datetime".datetime;
|
||||||
|
local json = require "util.json"
|
||||||
|
local formdecode = require "net.http".formdecode;
|
||||||
|
local http = require "net.http";
|
||||||
|
|
||||||
|
local mod_muc = module:depends"muc";
|
||||||
|
local rooms = rawget(mod_muc, "rooms");
|
||||||
|
local get_room_from_jid = rawget(mod_muc, "get_room_from_jid") or
|
||||||
|
function (room_jid)
|
||||||
|
return rooms[room_jid];
|
||||||
|
end
|
||||||
|
|
||||||
|
local routing = module:get_option("outgoing_webhook_routing") or {};
|
||||||
|
local listen_path = module:get_option("incoming_webhook_path") or "/webhook";
|
||||||
|
local default_from_nick = module:get_option("incoming_webhook_default_nick") or "Bot";
|
||||||
|
|
||||||
|
function postcallback(_, code)
|
||||||
|
module:log("debug", "HTTP result %d", code)
|
||||||
|
end
|
||||||
|
|
||||||
|
function check_message(data)
|
||||||
|
local stanza = data.stanza;
|
||||||
|
|
||||||
|
local this_room = get_room_from_jid(stanza.attr.to);
|
||||||
|
if not this_room then return; end -- no such room
|
||||||
|
|
||||||
|
local from_room_jid = this_room._jid_nick[stanza.attr.from];
|
||||||
|
if not from_room_jid then return; end -- no such nick
|
||||||
|
|
||||||
|
local from_room, from_host, from_nick = jid.split(from_room_jid);
|
||||||
|
|
||||||
|
local body = stanza:get_child("body");
|
||||||
|
if not body then return; end -- No body, like topic changes
|
||||||
|
body = body and body:get_text(); -- I feel like I want to do `or ""` there :/
|
||||||
|
|
||||||
|
if not routing[from_room] then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local json_out = {
|
||||||
|
channel_name = from_room,
|
||||||
|
timestamp = now(),
|
||||||
|
text = body,
|
||||||
|
team_domain = from_host,
|
||||||
|
user_name = from_nick,
|
||||||
|
};
|
||||||
|
local stanzaid = stanza:get_child("id");
|
||||||
|
if stanzaid and string.sub(stanzaid,1,string.len("webhookbot"))=="webhookbot" then
|
||||||
|
json_out["bot_id"] = "webhookbot";
|
||||||
|
end
|
||||||
|
|
||||||
|
json_out = json.encode(json_out)
|
||||||
|
local url = routing[from_room];
|
||||||
|
module:log("debug", "message from %s in %s to %s", from_nick, from_room, url);
|
||||||
|
if url == "DEBUG" then
|
||||||
|
module:log("debug", "json_out = %s", json_out);
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
local headers = {
|
||||||
|
["Content-Type"] = "application/json",
|
||||||
|
};
|
||||||
|
http.request(url, { method = "POST", body = json_out, headers = headers }, postcallback)
|
||||||
|
end
|
||||||
|
|
||||||
|
module:hook("message/bare", check_message, 10);
|
||||||
|
|
||||||
|
local function route_post(f)
|
||||||
|
return function(event, path)
|
||||||
|
local bare_room = jid.join(path, module.host);
|
||||||
|
if not get_room_from_jid(bare_room) then
|
||||||
|
module:log("warn", "mod_slack_webhook: invalid JID: %s", bare_room);
|
||||||
|
return 404;
|
||||||
|
end
|
||||||
|
-- Check secret?
|
||||||
|
return f(event, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handle_post(event, path)
|
||||||
|
local request = event.request;
|
||||||
|
local headers = request.headers;
|
||||||
|
|
||||||
|
local body_type = headers.content_type;
|
||||||
|
local post_body;
|
||||||
|
if body_type == "application/x-www-form-urlencoded" then
|
||||||
|
post_body = formdecode(request.body);
|
||||||
|
elseif body_type == "application/json" then
|
||||||
|
post_body = json.decode(request.body)
|
||||||
|
if not post_body then
|
||||||
|
return 420;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return 422;
|
||||||
|
end
|
||||||
|
local text = post_body["text"];
|
||||||
|
local success = 201
|
||||||
|
if post_body["attachments"] then
|
||||||
|
local att = post_body["attachments"][1];
|
||||||
|
text = string.format("%s %s (%s)"..string.char(10).."%s", post_body["icon_emoji"], att["title"], att["title_link"], att["text"]);
|
||||||
|
event.response.status_code = 200
|
||||||
|
success = "ok"
|
||||||
|
end
|
||||||
|
local bare_room = jid.join(path, module.host);
|
||||||
|
local dest_room = get_room_from_jid(bare_room);
|
||||||
|
local from_nick = default_from_nick;
|
||||||
|
if post_body["username"] then
|
||||||
|
from_nick = post_body["username"];
|
||||||
|
end
|
||||||
|
local sender = jid.join(path, module.host, from_nick);
|
||||||
|
module:log("debug", "message to %s from %s", bare_room, sender);
|
||||||
|
module:log("debug", "body: %s", text);
|
||||||
|
local message = msg({ to = bare_room, from = sender, type = "groupchat", id="webhookbot" .. now()},text);
|
||||||
|
dest_room:broadcast_message(message, true);
|
||||||
|
return success;
|
||||||
|
end
|
||||||
|
|
||||||
|
module:provides("http", {
|
||||||
|
default_path = listen_path;
|
||||||
|
route = {
|
||||||
|
["POST /*"] = route_post(handle_post);
|
||||||
|
OPTIONS = function(e)
|
||||||
|
local headers = e.response.headers;
|
||||||
|
headers.allow = "POST";
|
||||||
|
headers.accept = "application/x-www-form-urlencoded, application/json";
|
||||||
|
return 200;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue