X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fcbi%2Fluasrc%2Fcbi.lua;h=f54d5ac9a42d3655d7874ce92c898250b02fd555;hp=a37e81e871ac24779d93f0a11e3bb2e09fb79337;hb=de4b0abeb9825f6d7438b0f563623a048782258e;hpb=7bcd7e67d4c17d614f22bbbdcabbe3a2a55c12d7 diff --git a/libs/cbi/luasrc/cbi.lua b/libs/cbi/luasrc/cbi.lua index a37e81e87..f54d5ac9a 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 @@ -38,6 +39,7 @@ local instanceof = luci.util.instanceof FORM_NODATA = 0 FORM_VALID = 1 FORM_INVALID = -1 +FORM_CHANGED = 2 AUTO = true @@ -51,6 +53,7 @@ function load(cbimap, ...) require("luci.config") require("luci.util") + local upldir = "/lib/uci/upload/" local cbidir = luci.util.libpath() .. "/model/cbi/" local func, err = loadfile(cbimap) or loadfile(cbidir..cbimap..".lua") assert(func, err) @@ -69,15 +72,68 @@ function load(cbimap, ...) return rawget(tbl, key) or _M[key] or _G[key] end})) - local maps = {func()} + local maps = { func() } + local uploads = { } + local has_upload = false for i, map in ipairs(maps) do if not instanceof(map, Node) then error("CBI map returns no valid map object!") return nil + else + map:prepare() + if map.upload_fields then + has_upload = true + for _, field in ipairs(map.upload_fields) do + uploads[ + field.config .. '.' .. + field.section.sectiontype .. '.' .. + field.option + ] = true + end + end end end + if has_upload then + local uci = luci.model.uci.cursor() + local prm = luci.http.context.request.message.params + local fd, cbid + + luci.http.setfilehandler( + function( field, chunk, eof ) + if not field then return end + if field.name and not cbid then + local c, s, o = field.name:gmatch( + "cbid%.([^%.]+)%.([^%.]+)%.([^%.]+)" + )() + + if c and s and o then + local t = uci:get( c, s ) + if t and uploads[c.."."..t.."."..o] then + local path = upldir .. field.name + fd = io.open(path, "w") + if fd then + cbid = field.name + prm[cbid] = path + end + end + end + end + + if field.name == cbid and fd then + fd:write(chunk) + end + + if eof and fd then + fd:close() + fd = nil + cbid = nil + end + end + ) + end + return maps end @@ -166,6 +222,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) @@ -242,6 +305,9 @@ function Map.get_scheme(self, sectiontype, option) end end +function Map.submitstate(self) + return luci.http.formvalue("cbi.submit") +end -- Chain foreign config function Map.chain(self, config) @@ -279,6 +345,19 @@ function Map.parse(self) for i, config in ipairs(self.parsechain) do self.uci:unload(config) end + if type(self.commit_handler) == "function" then + self:commit_handler(self:submitstate()) + end + end + + if self:submitstate() then + if self.save then + return self.changed and FORM_CHANGED or FORM_VALID + else + return FORM_INVALID + end + else + return FORM_NODATA end end @@ -374,11 +453,12 @@ function SimpleForm.parse(self, ...) end local state = - not luci.http.formvalue("cbi.submit") and 0 - or valid and 1 - or -1 + not self:submitstate() and FORM_NODATA + or valid and FORM_VALID + or FORM_INVALID self.dorender = not self.handle or self:handle(state, self.data) ~= false + return state end function SimpleForm.render(self, ...) @@ -387,6 +467,10 @@ function SimpleForm.render(self, ...) end end +function SimpleForm.submitstate(self) + return luci.http.formvalue("cbi.submit") +end + function SimpleForm.section(self, class, ...) if instanceof(class, AbstractSection) then local obj = class(self, ...) @@ -566,7 +650,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 @@ -623,7 +707,7 @@ end function Table.parse(self) for i, k in ipairs(self:cfgsections()) do - if luci.http.formvalue("cbi.submit") then + if self.map:submitstate() then Node.parse(self, k) end end @@ -686,7 +770,7 @@ function NamedSection.parse(self, novld) if active then AbstractSection.parse_dynamic(self, s) - if luci.http.formvalue("cbi.submit") then + if self.map:submitstate() then Node.parse(self, s) if not novld and not self.override_scheme and self.map.scheme then @@ -761,7 +845,7 @@ function TypedSection.parse(self, novld) local co for i, k in ipairs(self:cfgsections()) do AbstractSection.parse_dynamic(self, k) - if luci.http.formvalue("cbi.submit") then + if self.map:submitstate() then Node.parse(self, k) if not novld and not self.override_scheme and self.map.scheme then @@ -795,6 +879,9 @@ function TypedSection.parse(self, novld) if name and #name > 0 then created = self:create(name) and name + if not created then + self.invalid_cts = true + end end end end @@ -860,23 +947,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 - self.default = vs.default + 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 @@ -887,6 +982,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 @@ -930,7 +1027,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 @@ -980,14 +1077,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 @@ -1041,6 +1140,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 @@ -1094,23 +1207,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 @@ -1224,7 +1337,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 @@ -1248,7 +1361,8 @@ 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 = {} @@ -1286,3 +1400,58 @@ 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.formcreated(self, section) + return AbstractValue.formcreated(self, section) or + luci.http.formvalue("cbi.rlf."..section.."."..self.option) or + luci.http.formvalue("cbi.rlf."..section.."."..self.option..".x") +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 + + +FileBrowser = class(AbstractValue) + +function FileBrowser.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/browser" +end