mod_rest: Add special handling to catch MAM results from remote hosts
Makes MAM queries to remote hosts works.
As the comment says, MAM results from users' local archives or local
MUCs are returned via origin.send() which is provided in the event and
thus already worked. Results from remote hosts go via normal stanza
routing and events, which need this extra handling to catch.
This pattern of iq-set, message+, iq-result is generally limited to MAM.
Closest similar thing might be MUC join, but to really handle that you
would need the webhook callback mechanism.
local mod_muc = module:depends("muc")
local http = require "net.http"
local st = require "util.stanza"
local json = require "util.json"
local url_pattern = [[https://twitter.com/%S+/status/%S+]]
local xmlns_fasten = "urn:xmpp:fasten:0"
local xmlns_xhtml = "http://www.w3.org/1999/xhtml"
local twitter_apiv2_bearer_token = module:get_option_string("twitter_apiv2_bearer_token");
local function fetch_tweet_data(room, url, tweet_id, origin_id)
if not url then return; end
local options = {
method = "GET";
headers = { Authorization = "Bearer "..twitter_apiv2_bearer_token; };
};
http.request(
'https://api.twitter.com/2/tweets/'..tweet_id..'?expansions=author_id&tweet.fields=created_at,text&user.fields=id,name,username,profile_image_url',
options,
function(response_body, response_code, _)
if response_code ~= 200 then
module:log("debug", "Call to %s returned code %s and body %s", url, response_code, response_body)
return;
end
local response = json.decode(response_body);
if not response then return; end
if not response['data'] or not response['includes'] then return; end
local tweet = response['data'];
local author = response['includes']['users'][1];
local to = room.jid
local from = room and room.jid or module.host
local fastening = st.message({to = to, from = from, type = 'groupchat'}):tag("apply-to", {xmlns = xmlns_fasten, id = origin_id})
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:article:author',
content = author['username']
}
):up()
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:article:published_time',
content = tweet['created_at']
}
):up()
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:description',
content = tweet['text']
}
):up()
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:image',
content = author['profile_image_url']
}
):up()
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:title',
content = author['username']
}
):up()
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:type',
content = 'tweet'
}
):up()
fastening:tag(
"meta",
{
xmlns = xmlns_xhtml,
property = 'og:url',
content = 'https://twitter.com/'..author['username']..'/status/'..tweet['id']
}
):up()
mod_muc.get_room_from_jid(room.jid):broadcast_message(fastening)
module:log("debug", tostring(fastening))
end
)
end
local function tweet_handler(event)
local room, stanza = event.room, st.clone(event.stanza)
local body = stanza:get_child_text("body")
if not body then return; end
local origin_id = stanza:find("{urn:xmpp:sid:0}origin-id@id")
if not origin_id then return; end
for url in body:gmatch(url_pattern) do
local _, _, _, tweet_id = string.find(url, "https://twitter.com/(%S+)/status/(%S+)");
fetch_tweet_data(room, url, tweet_id, origin_id);
end
end
module:hook("muc-occupant-groupchat", tweet_handler)
module:hook("muc-message-is-historic", function (event)
local fastening = event.stanza:get_child('apply-to', xmlns_fasten)
if fastening and fastening:get_child('meta', xmlns_xhtml) then
return true
end
end);