X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fcbi%2Fluasrc%2Fcbi.lua;h=8cde0a1777df4ff3be878321868c2ee104c8722e;hb=6b3985b6be52063c09f779b6bc509bf84eedc660;hp=29dd3054fd90cae69a7b5785d2a88116b19cdcbd;hpb=63706a9f4391a56f7054c496f519e8ec5bebbe1f;p=project%2Fluci.git diff --git a/libs/cbi/luasrc/cbi.lua b/libs/cbi/luasrc/cbi.lua index 29dd3054f..8cde0a177 100644 --- a/libs/cbi/luasrc/cbi.lua +++ b/libs/cbi/luasrc/cbi.lua @@ -30,6 +30,7 @@ require("luci.template") require("luci.util") require("luci.http") require("luci.uvl") +require("luci.fs") local uci = require("luci.model.uci") local class = luci.util.class @@ -47,24 +48,27 @@ REMOVE_PREFIX = "cbi.rts." -- Loads a CBI map from given file, creating an environment and returns it function load(cbimap, ...) require("luci.fs") - require("luci.i18n") + local i18n = require "luci.i18n" require("luci.config") require("luci.util") local cbidir = luci.util.libpath() .. "/model/cbi/" - local func, err = loadfile(cbidir..cbimap..".lua") - - if not func then - return nil - end + local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua") + assert(func, err) luci.i18n.loadc("cbi") + luci.i18n.loadc("uvl") - luci.util.resfenv(func) - luci.util.updfenv(func, luci.cbi) - luci.util.extfenv(func, "translate", luci.i18n.translate) - luci.util.extfenv(func, "translatef", luci.i18n.translatef) - luci.util.extfenv(func, "arg", {...}) + local env = { + translate=i18n.translate, + translatef=i18n.translatef, + arg={...} + } + + setfenv(func, setmetatable(env, {__index = + function(tbl, key) + return rawget(tbl, key) or _M[key] or _G[key] + end})) local maps = {func()} @@ -72,6 +76,8 @@ function load(cbimap, ...) if not instanceof(map, Node) then error("CBI map returns no valid map object!") return nil + else + map:prepare() end end @@ -84,31 +90,43 @@ local function _uvl_validate_section(node, name) luci.uvl.STRICT_UNKNOWN_OPTIONS = false luci.uvl.STRICT_UNKNOWN_SECTIONS = false - local stat, err = node.map.validator:validate_section(node.config, name, co) - if err then - node.map.save = false - if err.code == luci.uvl.errors.ERR_DEPENDENCY then - node.tag_deperror[name] = true - else - node.tag_invalid[name] = true + local function tag_fields(e) + if e.option and node.fields[e.option] then + if node.fields[e.option].error then + node.fields[e.option].error[name] = e + else + node.fields[e.option].error = { [name] = e } + end + elseif e.childs then + for _, c in ipairs(e.childs) do tag_fields(c) end end - for i, v in ipairs(err.childs) do - if v.option and node.fields[v.option] then - if v.code == luci.uvl.errors.ERR_OPTION then - local subcode = v.childs and v.childs[1] and v.childs[1].code - if subcode == luci.uvl.errors.ERR_DEPENDENCY then - node.fields[v.option].tag_reqerror[name] = true - elseif subcode == luci.uvl.errors.ERR_OPT_REQUIRED then - node.fields[v.option].tag_missing[name] = true - node.tag_deperror[name] = true - else - node.fields[v.option].tag_invalid[name] = true - end - end + end + + local function tag_section(e) + local s = { } + for _, c in ipairs(e.childs) do + if c.childs and not c:is(luci.uvl.errors.ERR_DEPENDENCY) then + table.insert( s, c.childs[1]:string() ) + else + table.insert( s, c:string() ) + end + end + if #s > 0 then + if node.error then + node.error[name] = s + else + node.error = { [name] = s } end end end + local stat, err = node.map.validator:validate_section(node.config, name, co) + if err then + node.map.save = false + tag_fields(err) + tag_section(err) + end + end local function _uvl_strip_remote_dependencies(deps) @@ -151,6 +169,13 @@ function Node._i18n(self, config, section, option, title, description) end end +-- Prepare nodes +function Node.prepare(self, ...) + for k, child in ipairs(self.children) do + child:prepare(...) + end +end + -- Append child nodes function Node.append(self, obj) table.insert(self.children, obj) @@ -206,6 +231,7 @@ function Map.__init__(self, config, ...) self.config = config self.parsechain = {self.config} self.template = "cbi/map" + self.apply_on_parse = nil self.uci = uci.cursor() self.save = true if not self.uci:load(self.config) then @@ -214,7 +240,7 @@ function Map.__init__(self, config, ...) self.validator = luci.uvl.UVL() self.scheme = self.validator:get_scheme(self.config) - + end function Map.get_scheme(self, sectiontype, option) @@ -233,8 +259,8 @@ function Map.chain(self, config) end -- Use optimized UCI writing -function Map.parse(self, ...) - Node.parse(self, ...) +function Map.parse(self) + Node.parse(self) if self.save then for i, config in ipairs(self.parsechain) do @@ -243,19 +269,38 @@ function Map.parse(self, ...) if luci.http.formvalue("cbi.apply") then for i, config in ipairs(self.parsechain) do self.uci:commit(config) - self.uci:apply(config) - + -- Refresh data because commit changes section names self.uci:load(config) end - + if self.apply_on_parse then + self.uci:apply(self.parsechain) + else + self._apply = function() + local cmd = self.uci:apply(self.parsechain, true) + return io.popen(cmd) + end + end + -- Reparse sections - Node.parse(self, ...) - + Node.parse(self, true) + end for i, config in ipairs(self.parsechain) do self.uci:unload(config) end + if type(self.commit_handler) == "function" then + self:commit_handler() + end + end +end + +function Map.render(self, ...) + Node.render(self, ...) + if self._apply then + local fp = self._apply() + fp:read("*a") + fp:close() end end @@ -534,7 +579,7 @@ function AbstractSection.create(self, section) local stat if section then - stat = self.map:set(section, nil, self.sectiontype) + stat = section:match("^%w+$") and self.map:set(section, nil, self.sectiontype) else section = self.map:add(self.sectiontype) stat = section @@ -617,7 +662,7 @@ NamedSection = class(AbstractSection) function NamedSection.__init__(self, map, section, stype, ...) AbstractSection.__init__(self, map, stype, ...) Node._i18n(self, map.config, section, nil, ...) - + -- Defaults self.addremove = false @@ -634,7 +679,7 @@ function NamedSection.__init__(self, map, section, stype, ...) self.section = section end -function NamedSection.parse(self) +function NamedSection.parse(self, novld) local s = self.section local active = self:cfgvalue(s) @@ -656,8 +701,8 @@ function NamedSection.parse(self) AbstractSection.parse_dynamic(self, s) if luci.http.formvalue("cbi.submit") then Node.parse(self, s) - - if not self.override_scheme and self.map.scheme then + + if not novld and not self.override_scheme and self.map.scheme then _uvl_validate_section(self, s) end end @@ -711,12 +756,15 @@ function TypedSection.depends(self, option, value) table.insert(self.deps, {option=option, value=value}) end -function TypedSection.parse(self) +function TypedSection.parse(self, novld) if self.addremove then -- Remove local crval = REMOVE_PREFIX .. self.config local name = luci.http.formvaluetable(crval) for k,v in pairs(name) do + if k:sub(-2) == ".x" then + k = k:sub(1, #k - 2) + end if self:cfgvalue(k) and self:checkscope(k) then self:remove(k) end @@ -728,8 +776,8 @@ function TypedSection.parse(self) AbstractSection.parse_dynamic(self, k) if luci.http.formvalue("cbi.submit") then Node.parse(self, k) - - if not self.override_scheme and self.map.scheme then + + if not novld and not self.override_scheme and self.map.scheme then _uvl_validate_section(self, k) end end @@ -738,11 +786,12 @@ function TypedSection.parse(self) if self.addremove then -- Create + local created local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype local name = luci.http.formvalue(crval) if self.anonymous then if name then - self:create() + created = self:create() end else if name then @@ -758,10 +807,17 @@ function TypedSection.parse(self) end if name and #name > 0 then - self:create(name) + created = self:create(name) and name + if not created then + self.invalid_cts = true + end end end end + + if created then + AbstractSection.parse_optionals(self, created) + end end end @@ -820,22 +876,31 @@ function AbstractValue.__init__(self, map, section, option, ...) self.tag_reqerror = {} self.tag_error = {} self.deps = {} - self.cast = "string" + --self.cast = "string" self.track_missing = false - self.rmempty = false + --self.rmempty = false self.default = nil self.size = nil self.optional = false +end +function AbstractValue.prepare(self) -- Use defaults from UVL if not self.override_scheme and self.map:get_scheme(self.section.sectiontype, self.option) then local vs = self.map:get_scheme(self.section.sectiontype, self.option) - self.rmempty = not vs.required - self.cast = (vs.type == "list") and "list" or "string" + if self.rmempty == nil then + self.rmempty = not vs.required + end + if self.cast == nil then + self.cast = (vs.type == "list") and "list" or "string" + end self.title = self.title or vs.title self.description = self.description or vs.descr + if self.default == nil then + self.default = vs.default + end if vs.depends and not self.override_dependencies then for i, deps in ipairs(vs.depends) do @@ -846,6 +911,8 @@ function AbstractValue.__init__(self, map, section, option, ...) end end end + + self.cast = self.cast or "string" end -- Add a dependencie to another section field @@ -889,7 +956,7 @@ function AbstractValue.parse(self, section) local fvalue = self:formvalue(section) local cvalue = self:cfgvalue(section) - if fvalue and fvalue ~= "" then -- If we have a form value, write it to UCI + if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI fvalue = self:transform(self:validate(fvalue, section)) if not fvalue then self.tag_invalid[section] = true @@ -939,14 +1006,16 @@ end -- Return the UCI value of this object function AbstractValue.cfgvalue(self, section) local value = self.map:get(section, self.option) - if not self.cast or self.cast == type(value) then + if not value then + return nil + elseif not self.cast or self.cast == type(value) then return value elseif self.cast == "string" then if type(value) == "table" then return value[1] end elseif self.cast == "table" then - return {value} + return luci.util.split(value, "%s+", nil, true) end end @@ -1000,6 +1069,20 @@ function DummyValue.__init__(self, ...) self.value = nil end +function DummyValue.cfgvalue(self, section) + local value + if self.value then + if type(self.value) == "function" then + value = self:value(section) + else + value = self.value + end + else + value = AbstractValue.cfgvalue(self, section) + end + return value +end + function DummyValue.parse(self) end @@ -1053,23 +1136,23 @@ function ListValue.__init__(self, ...) self.vallist = {} self.size = 1 self.widget = "select" +end +function ListValue.prepare(self, ...) + AbstractValue.prepare(self, ...) if not self.override_scheme and self.map:get_scheme(self.section.sectiontype, self.option) then local vs = self.map:get_scheme(self.section.sectiontype, self.option) - if self.value and vs.values and not self.override_values then - if self.rmempty or self.optional then - self:value("") - end - for k, v in pairs(vs.values) do + if self.value and vs.valuelist and not self.override_values then + for k, v in ipairs(vs.valuelist) do local deps = {} if not self.override_dependencies - and vs.enum_depends and vs.enum_depends[k] then - for i, dep in ipairs(vs.enum_depends[k]) do + and vs.enum_depends and vs.enum_depends[v.value] then + for i, dep in ipairs(vs.enum_depends[v.value]) do table.insert(deps, _uvl_strip_remote_dependencies(dep)) end end - self:value(k, v, unpack(deps)) + self:value(v.value, v.title or v.value, unpack(deps)) end end end @@ -1183,7 +1266,7 @@ function StaticList.validate(self, value) local valid = {} for i, v in ipairs(value) do - if luci.util.contains(self.valuelist, v) then + if luci.util.contains(self.vallist, v) then table.insert(valid, v) end end @@ -1207,13 +1290,15 @@ function DynamicList.value(self, key, val) table.insert(self.vallist, tostring(val)) end -function DynamicList.validate(self, value, section) +function DynamicList.formvalue(self, section) + local value = AbstractValue.formvalue(self, section) value = (type(value) == "table") and value or {value} local valid = {} for i, v in ipairs(value) do - if v and #v > 0 and - not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i) then + if v and #v > 0 + and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i) + and not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then table.insert(valid, v) end end @@ -1244,3 +1329,44 @@ function Button.__init__(self, ...) self.inputstyle = nil self.rmempty = true end + + +FileUpload = class(AbstractValue) + +function FileUpload.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/upload" + if not self.map.upload_fields then + self.map.upload_fields = { self } + else + self.map.upload_fields[#self.map.upload_fields+1] = self + end +end + +function FileUpload.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val and luci.fs.access(val) then + return val + end + return nil +end + +function FileUpload.formvalue(self, section) + local val = AbstractValue.formvalue(self, section) + if val then + if not luci.http.formvalue("cbi.rlf."..section.."."..self.option) and + not luci.http.formvalue("cbi.rlf."..section.."."..self.option..".x") + then + return val + end + luci.fs.unlink(val) + self.value = nil + end + return nil +end + +function FileUpload.remove(self, section) + local val = AbstractValue.formvalue(self, section) + if val and luci.fs.access(val) then luci.fs.unlink(val) end + return AbstractValue.remove(self, section) +end