Software / code / prosody-modules
Comparison
mod_rest/jsonmap.lib.lua @ 3922:ea59c9455f93
mod_rest: Move dataforms into structure for more logical code order
Needs that `local x; x = ...` trick to make the mapping table be in
scope for all the inner functions.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Fri, 28 Feb 2020 22:24:49 +0100 |
| parent | 3912:1df4900bbd29 |
| child | 3923:3c3d216c6f6d |
comparison
equal
deleted
inserted
replaced
| 3921:9eabd68b8e48 | 3922:ea59c9455f93 |
|---|---|
| 2 local jid = require "util.jid"; | 2 local jid = require "util.jid"; |
| 3 local json = require "util.json"; | 3 local json = require "util.json"; |
| 4 local st = require "util.stanza"; | 4 local st = require "util.stanza"; |
| 5 local xml = require "util.xml"; | 5 local xml = require "util.xml"; |
| 6 | 6 |
| 7 -- Reused in many XEPs so declared up here | 7 local field_mappings; -- in scope for "func" mappings |
| 8 local dataform = { | 8 field_mappings = { |
| 9 -- Generic and complete dataforms mapping | |
| 10 type = "func", xmlns = "jabber:x:data", tagname = "x", | |
| 11 st2json = function (s) | |
| 12 local fields = array(); | |
| 13 local form = { | |
| 14 type = s.attr.type; | |
| 15 title = s:get_child_text("title"); | |
| 16 instructions = s:get_child_text("instructions"); | |
| 17 fields = fields; | |
| 18 }; | |
| 19 for field in s:childtags("field") do | |
| 20 local i = { | |
| 21 var = field.attr.var; | |
| 22 type = field.attr.type; | |
| 23 label = field.attr.label; | |
| 24 desc = field:get_child_text("desc"); | |
| 25 required = field:get_child("required") and true or nil; | |
| 26 value = field:get_child_text("value"); | |
| 27 }; | |
| 28 if field.attr.type == "jid-multi" or field.attr.type == "list-multi" or field.attr.type == "text-multi" then | |
| 29 local value = array(); | |
| 30 for v in field:childtags("value") do | |
| 31 value:push(v:get_text()); | |
| 32 end | |
| 33 if field.attr.type == "text-multi" then | |
| 34 i.value = value:concat("\n"); | |
| 35 else | |
| 36 i.value = value; | |
| 37 end | |
| 38 end | |
| 39 if field.attr.type == "list-single" or field.attr.type == "list-multi" then | |
| 40 local options = array(); | |
| 41 for o in field:childtags("option") do | |
| 42 options:push({ label = o.attr.label, value = o:get_child_text("value") }); | |
| 43 end | |
| 44 i.options = options; | |
| 45 end | |
| 46 fields:push(i); | |
| 47 end | |
| 48 return form; | |
| 49 end; | |
| 50 json2st = function (x) | |
| 51 if type(x) == "table" and x ~= json.null then | |
| 52 local form = st.stanza("x", { xmlns = "jabber:x:data", type = x.type }); | |
| 53 if x.title then | |
| 54 form:text_tag("title", x.title); | |
| 55 end | |
| 56 if x.instructions then | |
| 57 form:text_tag("instructions", x.instructions); | |
| 58 end | |
| 59 if type(x.fields) == "table" then | |
| 60 for _, f in ipairs(x.fields) do | |
| 61 if type(f) == "table" then | |
| 62 form:tag("field", { var = f.var, type = f.type, label = f.label }); | |
| 63 if f.desc then | |
| 64 form:text_tag("desc", f.desc); | |
| 65 end | |
| 66 if f.required == true then | |
| 67 form:tag("required"):up(); | |
| 68 end | |
| 69 if type(f.value) == "string" then | |
| 70 form:text_tag("value", f.value); | |
| 71 elseif type(f.value) == "table" then | |
| 72 for _, v in ipairs(f.value) do | |
| 73 form:text_tag("value", v); | |
| 74 end | |
| 75 end | |
| 76 if type(f.options) == "table" then | |
| 77 for _, o in ipairs(f.value) do | |
| 78 if type(o) == "table" then | |
| 79 form:tag("option", { label = o.label }); | |
| 80 form:text_tag("value", o.value); | |
| 81 form:up(); | |
| 82 end | |
| 83 end | |
| 84 end | |
| 85 end | |
| 86 end | |
| 87 end | |
| 88 return form; | |
| 89 end | |
| 90 end; | |
| 91 }; | |
| 92 | |
| 93 local function formdata(s, t) | |
| 94 local form = st.stanza("x", { xmlns = "jabber:x:data", type = t }); | |
| 95 for k, v in pairs(s) do | |
| 96 form:tag("field", { var = k }); | |
| 97 if type(v) == "string" then | |
| 98 form:text_tag("value", v); | |
| 99 elseif type(v) == "table" then | |
| 100 for _, v_ in ipairs(v) do | |
| 101 form:text_tag("value", v_); | |
| 102 end | |
| 103 end | |
| 104 end | |
| 105 return form; | |
| 106 end | |
| 107 | |
| 108 local field_mappings = { | |
| 109 -- top level stanza attributes | 9 -- top level stanza attributes |
| 110 -- needed here to mark them as known fields | 10 -- needed here to mark them as known fields |
| 111 kind = "attr", | 11 kind = "attr", |
| 112 type = "attr", | 12 type = "attr", |
| 113 to = "attr", | 13 to = "attr", |
| 259 type = note.attr.type; | 159 type = note.attr.type; |
| 260 text = note:get_text(); | 160 text = note:get_text(); |
| 261 }; | 161 }; |
| 262 end | 162 end |
| 263 if form then | 163 if form then |
| 264 cmd.form = dataform.st2json(form); | 164 cmd.form = field_mappings.dataform.st2json(form); |
| 265 end | 165 end |
| 266 return cmd; | 166 return cmd; |
| 267 end; | 167 end; |
| 268 json2st = function (s) | 168 json2st = function (s) |
| 269 if type(s) == "table" and s ~= json.null then | 169 if type(s) == "table" and s ~= json.null then |
| 290 cmd:up(); | 190 cmd:up(); |
| 291 elseif type(s.note) == "table" then | 191 elseif type(s.note) == "table" then |
| 292 cmd:text_tag("note", s.note.text, { type = s.note.type }); | 192 cmd:text_tag("note", s.note.text, { type = s.note.type }); |
| 293 end | 193 end |
| 294 if s.form then | 194 if s.form then |
| 295 cmd:add_child(dataform.json2st(s.form)); | 195 cmd:add_child(field_mappings.dataform.json2st(s.form)); |
| 296 elseif s.data then | 196 elseif s.data then |
| 297 cmd:add_child(formdata(s.data)); | 197 cmd:add_child(field_mappings.formdata.json2st(s.data)); |
| 298 end | 198 end |
| 299 return cmd; | 199 return cmd; |
| 300 elseif type(s) == "string" then -- assume node | 200 elseif type(s) == "string" then -- assume node |
| 301 return st.stanza("command", { xmlns = "http://jabber.org/protocol/commands", node = s }); | 201 return st.stanza("command", { xmlns = "http://jabber.org/protocol/commands", node = s }); |
| 302 end | 202 end |
| 335 end; | 235 end; |
| 336 end | 236 end |
| 337 }; | 237 }; |
| 338 | 238 |
| 339 -- XEP-0004: Data Forms | 239 -- XEP-0004: Data Forms |
| 340 dataform = dataform; | 240 dataform = { |
| 341 | 241 -- Generic and complete dataforms mapping |
| 342 -- Simpler mapping from JSON map | 242 type = "func", xmlns = "jabber:x:data", tagname = "x", |
| 243 st2json = function (s) | |
| 244 local fields = array(); | |
| 245 local form = { | |
| 246 type = s.attr.type; | |
| 247 title = s:get_child_text("title"); | |
| 248 instructions = s:get_child_text("instructions"); | |
| 249 fields = fields; | |
| 250 }; | |
| 251 for field in s:childtags("field") do | |
| 252 local i = { | |
| 253 var = field.attr.var; | |
| 254 type = field.attr.type; | |
| 255 label = field.attr.label; | |
| 256 desc = field:get_child_text("desc"); | |
| 257 required = field:get_child("required") and true or nil; | |
| 258 value = field:get_child_text("value"); | |
| 259 }; | |
| 260 if field.attr.type == "jid-multi" or field.attr.type == "list-multi" or field.attr.type == "text-multi" then | |
| 261 local value = array(); | |
| 262 for v in field:childtags("value") do | |
| 263 value:push(v:get_text()); | |
| 264 end | |
| 265 if field.attr.type == "text-multi" then | |
| 266 i.value = value:concat("\n"); | |
| 267 else | |
| 268 i.value = value; | |
| 269 end | |
| 270 end | |
| 271 if field.attr.type == "list-single" or field.attr.type == "list-multi" then | |
| 272 local options = array(); | |
| 273 for o in field:childtags("option") do | |
| 274 options:push({ label = o.attr.label, value = o:get_child_text("value") }); | |
| 275 end | |
| 276 i.options = options; | |
| 277 end | |
| 278 fields:push(i); | |
| 279 end | |
| 280 return form; | |
| 281 end; | |
| 282 json2st = function (x) | |
| 283 if type(x) == "table" and x ~= json.null then | |
| 284 local form = st.stanza("x", { xmlns = "jabber:x:data", type = x.type }); | |
| 285 if x.title then | |
| 286 form:text_tag("title", x.title); | |
| 287 end | |
| 288 if x.instructions then | |
| 289 form:text_tag("instructions", x.instructions); | |
| 290 end | |
| 291 if type(x.fields) == "table" then | |
| 292 for _, f in ipairs(x.fields) do | |
| 293 if type(f) == "table" then | |
| 294 form:tag("field", { var = f.var, type = f.type, label = f.label }); | |
| 295 if f.desc then | |
| 296 form:text_tag("desc", f.desc); | |
| 297 end | |
| 298 if f.required == true then | |
| 299 form:tag("required"):up(); | |
| 300 end | |
| 301 if type(f.value) == "string" then | |
| 302 form:text_tag("value", f.value); | |
| 303 elseif type(f.value) == "table" then | |
| 304 for _, v in ipairs(f.value) do | |
| 305 form:text_tag("value", v); | |
| 306 end | |
| 307 end | |
| 308 if type(f.options) == "table" then | |
| 309 for _, o in ipairs(f.value) do | |
| 310 if type(o) == "table" then | |
| 311 form:tag("option", { label = o.label }); | |
| 312 form:text_tag("value", o.value); | |
| 313 form:up(); | |
| 314 end | |
| 315 end | |
| 316 end | |
| 317 end | |
| 318 end | |
| 319 end | |
| 320 return form; | |
| 321 end | |
| 322 end; | |
| 323 }; | |
| 324 | |
| 325 -- Simpler mapping of dataform from JSON map | |
| 343 formdata = { type = "func", xmlns = "jabber:x:data", tagname = "", | 326 formdata = { type = "func", xmlns = "jabber:x:data", tagname = "", |
| 344 st2json = function () | 327 st2json = function () |
| 345 -- Tricky to do in a generic way without each form layout | 328 -- Tricky to do in a generic way without each form layout |
| 346 -- In the future, some well-known layouts might be understood | 329 -- In the future, some well-known layouts might be understood |
| 347 return nil, "not-implemented"; | 330 return nil, "not-implemented"; |
| 348 end, | 331 end, |
| 349 json2st = formdata, | 332 json2st = function (s, t) |
| 333 local form = st.stanza("x", { xmlns = "jabber:x:data", type = t }); | |
| 334 for k, v in pairs(s) do | |
| 335 form:tag("field", { var = k }); | |
| 336 if type(v) == "string" then | |
| 337 form:text_tag("value", v); | |
| 338 elseif type(v) == "table" then | |
| 339 for _, v_ in ipairs(v) do | |
| 340 form:text_tag("value", v_); | |
| 341 end | |
| 342 end | |
| 343 end | |
| 344 return form; | |
| 345 end | |
| 350 }; | 346 }; |
| 351 }; | 347 }; |
| 352 | 348 |
| 353 local implied_kinds = { | 349 local implied_kinds = { |
| 354 disco = "iq", | 350 disco = "iq", |