Comparison

util/dataforms.lua @ 9243:a4c52e304e6f

util.dataforms: Add support for XEP-0122: Data Forms Validation Initially only basic validation of xs:integer
author Kim Alvefur <zash@zash.se>
date Sat, 01 Sep 2018 03:10:09 +0200
parent 9242:68694c1bd960
child 9246:397e8e5a2f1f
comparison
equal deleted inserted replaced
9242:68694c1bd960 9243:a4c52e304e6f
7 -- 7 --
8 8
9 local setmetatable = setmetatable; 9 local setmetatable = setmetatable;
10 local ipairs = ipairs; 10 local ipairs = ipairs;
11 local type, next = type, next; 11 local type, next = type, next;
12 local tonumber = tonumber;
12 local t_concat = table.concat; 13 local t_concat = table.concat;
13 local st = require "util.stanza"; 14 local st = require "util.stanza";
14 local jid_prep = require "util.jid".prep; 15 local jid_prep = require "util.jid".prep;
15 16
16 local _ENV = nil; 17 local _ENV = nil;
17 -- luacheck: std none 18 -- luacheck: std none
18 19
19 local xmlns_forms = 'jabber:x:data'; 20 local xmlns_forms = 'jabber:x:data';
21 local xmlns_validate = 'http://jabber.org/protocol/xdata-validate';
20 22
21 local form_t = {}; 23 local form_t = {};
22 local form_mt = { __index = form_t }; 24 local form_mt = { __index = form_t };
23 25
24 local function new(layout) 26 local function new(layout)
47 if formtype ~= "submit" then 49 if formtype ~= "submit" then
48 if field.desc then 50 if field.desc then
49 form:text_tag("desc", field.desc); 51 form:text_tag("desc", field.desc);
50 end 52 end
51 end 53 end
54
55 if formtype == "form" and field.datatype then
56 form:tag("validate", { xmlns = xmlns_validate, datatype = field.datatype });
57 -- <basic/> assumed
58 form:up();
59 end
60
52 61
53 local value = field.value; 62 local value = field.value;
54 local options = field.options; 63 local options = field.options;
55 64
56 if data and data[field.name] ~= nil then 65 if data and data[field.name] ~= nil then
83 end 92 end
84 end 93 end
85 end 94 end
86 95
87 if value ~= nil then 96 if value ~= nil then
97 if type(value) == "number" then
98 -- TODO validate that this is ok somehow, eg check field.datatype
99 value = ("%g"):format(value);
100 end
88 -- Add value, depending on type 101 -- Add value, depending on type
89 if field_type == "hidden" then 102 if field_type == "hidden" then
90 if type(value) == "table" then 103 if type(value) == "table" then
91 -- Assume an XML snippet 104 -- Assume an XML snippet
92 form:tag("value") 105 form:tag("value")
139 end 152 end
140 return form; 153 return form;
141 end 154 end
142 155
143 local field_readers = {}; 156 local field_readers = {};
157 local data_validators = {};
144 158
145 function form_t.data(layout, stanza, current) 159 function form_t.data(layout, stanza, current)
146 local data = {}; 160 local data = {};
147 local errors = {}; 161 local errors = {};
148 local present = {}; 162 local present = {};
164 end 178 end
165 elseif field.name then 179 elseif field.name then
166 present[field.name] = true; 180 present[field.name] = true;
167 local reader = field_readers[field.type]; 181 local reader = field_readers[field.type];
168 if reader then 182 if reader then
169 data[field.name], errors[field.name] = reader(tag, field.required); 183 local value, err = reader(tag, field.required);
184 local validator = field.datatype and data_validators[field.datatype];
185 if value ~= nil and validator then
186 local valid, ret = validator(value, field);
187 if valid then
188 value = ret;
189 else
190 value, err = nil, ret or field.datatype;
191 end
192 end
193 data[field.name], errors[field.name] = value, err;
170 end 194 end
171 end 195 end
172 end 196 end
173 if next(errors) then 197 if next(errors) then
174 return data, errors, present; 198 return data, errors, present;
263 field_readers["hidden"] = 287 field_readers["hidden"] =
264 function (field_tag) 288 function (field_tag)
265 return field_tag:get_child_text("value"); 289 return field_tag:get_child_text("value");
266 end 290 end
267 291
292 data_validators["xs:integer"] =
293 function (data)
294 local n = tonumber(data);
295 if not n then
296 return false, "not a number";
297 elseif n % 1 ~= 0 then
298 return false, "not an integer";
299 end
300 return true, n;
301 end
302
268 303
269 local function get_form_type(form) 304 local function get_form_type(form)
270 if not st.is_stanza(form) then 305 if not st.is_stanza(form) then
271 return nil, "not a stanza object"; 306 return nil, "not a stanza object";
272 elseif form.attr.xmlns ~= "jabber:x:data" or form.name ~= "x" then 307 elseif form.attr.xmlns ~= "jabber:x:data" or form.name ~= "x" then