Changeset

3953:2c6d5734ae04

mod_rest: Add JSON mapping of XEP-0128: Service Discovery Extensions Example XEP-0157 payload: { "disco" : { "extensions" : { "http://jabber.org/network/serverinfo" : { "abuse-addresses" : [ "mailto:abuse@shakespeare.lit", "xmpp:abuse@shakespeare.lit" ], "admin-addresses" : [ "mailto:admin@shakespeare.lit", "xmpp:admin@shakespeare.lit" ], "feedback-addresses" : [ "http://shakespeare.lit/feedback.php", "mailto:feedback@shakespeare.lit", "xmpp:feedback@shakespeare.lit" ], "sales-addresses" : [ "xmpp:bard@shakespeare.lit" ], "security-addresses" : [ "xmpp:security@shakespeare.lit" ], "support-addresses" : [ "http://shakespeare.lit/support.php", "xmpp:support@shakespeare.lit" ] } } } }
author Kim Alvefur <zash@zash.se>
date Mon, 23 Mar 2020 19:03:04 +0100
parents 3952:343dc9dd70dd
children 3954:7a2998e48545
files mod_rest/README.markdown mod_rest/jsonmap.lib.lua
diffstat 2 files changed, 44 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mod_rest/README.markdown	Sat Mar 21 18:05:22 2020 +0100
+++ b/mod_rest/README.markdown	Mon Mar 23 19:03:04 2020 +0100
@@ -375,6 +375,11 @@
     items list query. The response contain an array of items like
     `{"jid":"xmpp.address.here","name":"Description of item"}`.
 
+`extensions`
+:   Map of extended feature discovery (see [XEP-0128]) data with
+    `FORM_DATA` fields as the keys pointing at maps with the rest of the
+    data.
+
 #### Ad-Hoc Commands
 
 Used to execute arbitrary commands on supporting entities.
--- a/mod_rest/jsonmap.lib.lua	Sat Mar 21 18:05:22 2020 +0100
+++ b/mod_rest/jsonmap.lib.lua	Mon Mar 23 19:03:04 2020 +0100
@@ -75,7 +75,7 @@
 	disco = {
 		type = "func", xmlns = "http://jabber.org/protocol/disco#info", tagname = "query",
 		st2json = function (s) --> array of features
-			local identities, features = array(), array();
+			local identities, features, extensions = array(), array(), {};
 			for tag in s:childtags() do
 				if tag.name == "identity" and tag.attr.category and tag.attr.type then
 					identities:push({ category = tag.attr.category, type = tag.attr.type, name = tag.attr.name });
@@ -83,7 +83,16 @@
 					features:push(tag.attr.var);
 				end
 			end
-			return { node = s.attr.node, identities = identities, features = features, };
+			for form in s:childtags("x", "jabber:x:data") do
+				local jform = field_mappings.formdata.st2json(form);
+				local form_type = jform["FORM_TYPE"];
+				if jform then
+					jform["FORM_TYPE"] = nil;
+					extensions[form_type] = jform;
+				end
+			end
+			if next(extensions) == nil then extensions = nil; end
+			return { node = s.attr.node, identities = identities, features = features, extensions = extensions };
 		end;
 		json2st = function (s)
 			if type(s) == "table" and s ~= json.null then
@@ -98,6 +107,12 @@
 						disco:tag("feature", { var = feature }):up();
 					end
 				end
+				if s.extensions then
+					for form_type, extension in pairs(s.extensions) do
+						extension["FORM_TYPE"] = form_type;
+						disco:add_child(field_mappings.formdata.json2st(extension));
+					end
+				end
 				return disco;
 			else
 				return st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info", });
@@ -324,10 +339,28 @@
 
 	-- Simpler mapping of dataform from JSON map
 	formdata = { type = "func", xmlns = "jabber:x:data", tagname = "",
-		st2json = function ()
-			-- Tricky to do in a generic way without each form layout
-			-- In the future, some well-known layouts might be understood
-			return nil, "not-implemented";
+		st2json = function (s)
+			local r = {};
+			for field in s:childtags("field") do
+				if field.attr.var then
+					local values = array();
+					for value in field:childtags("value") do
+						values:push(value:get_text());
+					end
+					if field.attr.type == "list-single" or field.attr.type == "list-multi" then
+						r[field.attr.var] = values;
+					elseif field.attr.type == "text-multi" then
+						r[field.attr.var] = values:concat("\n");
+					elseif field.attr.type == "boolean" then
+						r[field.attr.var] = values[1] == "1" or values[1] == "true";
+					elseif field.attr.type then
+						r[field.attr.var] = values[1] or json.null;
+					else -- type is optional, no way to know if multiple or single value is expected
+						r[field.attr.var] = values;
+					end
+				end
+			end
+			return r;
 		end,
 		json2st = function (s, t)
 			local form = st.stanza("x", { xmlns = "jabber:x:data", type = t });