aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2018-09-01 03:10:09 +0200
committerKim Alvefur <zash@zash.se>2018-09-01 03:10:09 +0200
commit080c294fe8e2c1ef03297284365636ba4a37d66b (patch)
treec3b5e65c45bcd1366d6e884ff5420c147a19b015
parent367e73a610e687ae01a6987023683d3ea9eac805 (diff)
downloadprosody-080c294fe8e2c1ef03297284365636ba4a37d66b.tar.gz
prosody-080c294fe8e2c1ef03297284365636ba4a37d66b.zip
util.dataforms: Add support for XEP-0122: Data Forms Validation
Initially only basic validation of xs:integer
-rw-r--r--spec/util_dataforms_spec.lua22
-rw-r--r--util/dataforms.lua37
2 files changed, 58 insertions, 1 deletions
diff --git a/spec/util_dataforms_spec.lua b/spec/util_dataforms_spec.lua
index 123b9f8a..89759035 100644
--- a/spec/util_dataforms_spec.lua
+++ b/spec/util_dataforms_spec.lua
@@ -401,5 +401,27 @@ describe("util.dataforms", function ()
assert.equal("hello", x:find"field/value#");
end);
end);
+
+ describe("validation", function ()
+ local f = dataforms.new {
+ {
+ name = "number",
+ type = "text-single",
+ datatype = "xs:integer",
+ },
+ };
+
+ it("works", function ()
+ local d = f:data(f:form({number = 1}));
+ assert.equal(1, d.number);
+ end);
+
+ it("works", function ()
+ local d,e = f:data(f:form({number = "nan"}));
+ assert.not_equal(1, d.number);
+ assert.table(e);
+ assert.string(e.number);
+ end);
+ end);
end);
diff --git a/util/dataforms.lua b/util/dataforms.lua
index 3ac18697..e866f502 100644
--- a/util/dataforms.lua
+++ b/util/dataforms.lua
@@ -9,6 +9,7 @@
local setmetatable = setmetatable;
local ipairs = ipairs;
local type, next = type, next;
+local tonumber = tonumber;
local t_concat = table.concat;
local st = require "util.stanza";
local jid_prep = require "util.jid".prep;
@@ -17,6 +18,7 @@ local _ENV = nil;
-- luacheck: std none
local xmlns_forms = 'jabber:x:data';
+local xmlns_validate = 'http://jabber.org/protocol/xdata-validate';
local form_t = {};
local form_mt = { __index = form_t };
@@ -50,6 +52,13 @@ function form_t.form(layout, data, formtype)
end
end
+ if formtype == "form" and field.datatype then
+ form:tag("validate", { xmlns = xmlns_validate, datatype = field.datatype });
+ -- <basic/> assumed
+ form:up();
+ end
+
+
local value = field.value;
local options = field.options;
@@ -85,6 +94,10 @@ function form_t.form(layout, data, formtype)
end
if value ~= nil then
+ if type(value) == "number" then
+ -- TODO validate that this is ok somehow, eg check field.datatype
+ value = ("%g"):format(value);
+ end
-- Add value, depending on type
if field_type == "hidden" then
if type(value) == "table" then
@@ -141,6 +154,7 @@ function form_t.form(layout, data, formtype)
end
local field_readers = {};
+local data_validators = {};
function form_t.data(layout, stanza, current)
local data = {};
@@ -166,7 +180,17 @@ function form_t.data(layout, stanza, current)
present[field.name] = true;
local reader = field_readers[field.type];
if reader then
- data[field.name], errors[field.name] = reader(tag, field.required);
+ local value, err = reader(tag, field.required);
+ local validator = field.datatype and data_validators[field.datatype];
+ if value ~= nil and validator then
+ local valid, ret = validator(value, field);
+ if valid then
+ value = ret;
+ else
+ value, err = nil, ret or field.datatype;
+ end
+ end
+ data[field.name], errors[field.name] = value, err;
end
end
end
@@ -265,6 +289,17 @@ field_readers["hidden"] =
return field_tag:get_child_text("value");
end
+data_validators["xs:integer"] =
+ function (data)
+ local n = tonumber(data);
+ if not n then
+ return false, "not a number";
+ elseif n % 1 ~= 0 then
+ return false, "not an integer";
+ end
+ return true, n;
+ end
+
local function get_form_type(form)
if not st.is_stanza(form) then