Mercurial > 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 |
parents | 1df4900bbd29 |
children | 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", |