From 080c294fe8e2c1ef03297284365636ba4a37d66b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 1 Sep 2018 03:10:09 +0200 Subject: util.dataforms: Add support for XEP-0122: Data Forms Validation Initially only basic validation of xs:integer --- spec/util_dataforms_spec.lua | 22 ++++++++++++++++++++++ util/dataforms.lua | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) 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 }); + -- 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 -- cgit v1.2.3