X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=modules%2Fluci-base%2Fluasrc%2Fcbi.lua;h=b5b2c8d8f201b5ca1cd3aec091720adfc83a0074;hp=ae570b1556bbaaf2ee43be598fc9899673def048;hb=986baa5ccee13692e9c1ef5a23535e15b7fcb948;hpb=1bb4822dca6113f73e3bc89e2acf15935e6f8e92 diff --git a/modules/luci-base/luasrc/cbi.lua b/modules/luci-base/luasrc/cbi.lua index ae570b155..b5b2c8d8f 100644 --- a/modules/luci-base/luasrc/cbi.lua +++ b/modules/luci-base/luasrc/cbi.lua @@ -1,29 +1,6 @@ ---[[ -LuCI - Configuration Bind Interface - -Description: -Offers an interface for binding configuration values to certain -data types. Supports value and range validation and basic dependencies. - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. -]]-- module("luci.cbi", package.seeall) require("luci.template") @@ -35,6 +12,7 @@ require("luci.http") local fs = require("nixio.fs") local uci = require("luci.model.uci") local datatypes = require("luci.cbi.datatypes") +local dispatcher = require("luci.dispatcher") local class = util.class local instanceof = util.instanceof @@ -330,8 +308,30 @@ function Map.__init__(self, config, ...) self.changed = false - if not self.uci:load(self.config) then - error("Unable to read UCI data: " .. self.config) + local path = "%s/%s" %{ self.uci:get_confdir(), self.config } + if fs.stat(path, "type") ~= "reg" then + fs.writefile(path, "") + end + + local ok, err = self.uci:load(self.config) + if not ok then + local url = dispatcher.build_url(unpack(dispatcher.context.request)) + local source = self:formvalue("cbi.source") + if type(source) == "string" then + fs.writefile(path, source:gsub("\r\n", "\n")) + ok, err = self.uci:load(self.config) + if ok then + luci.http.redirect(url) + end + end + self.save = false + end + + if not ok then + self.template = "cbi/error" + self.error = err + self.source = fs.readfile(path) or "" + self.pageaction = false end end @@ -367,63 +367,64 @@ end -- Use optimized UCI writing function Map.parse(self, readinput, ...) - self.readinput = (readinput ~= false) - self:_run_hooks("on_parse") - if self:formvalue("cbi.skip") then self.state = FORM_SKIP + elseif not self.save then + self.state = FORM_INVALID + elseif not self:submitstate() then + self.state = FORM_NODATA + end + + -- Back out early to prevent unauthorized changes on the subsequent parse + if self.state ~= nil then return self:state_handler(self.state) end + self.readinput = (readinput ~= false) + self:_run_hooks("on_parse") + Node.parse(self, ...) - if self.save then - self:_run_hooks("on_save", "on_before_save") + self:_run_hooks("on_save", "on_before_save") + for i, config in ipairs(self.parsechain) do + self.uci:save(config) + end + self:_run_hooks("on_after_save") + if (not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply") then + self:_run_hooks("on_before_commit") for i, config in ipairs(self.parsechain) do - self.uci:save(config) - end - self:_run_hooks("on_after_save") - if self:submitstate() and ((not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply")) then - self:_run_hooks("on_before_commit") - for i, config in ipairs(self.parsechain) do - self.uci:commit(config) - - -- Refresh data because commit changes section names - self.uci:load(config) - end - self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") - if self.apply_on_parse then - self.uci:apply(self.parsechain) - self:_run_hooks("on_apply", "on_after_apply") - else - -- This is evaluated by the dispatcher and delegated to the - -- template which in turn fires XHR to perform the actual - -- apply actions. - self.apply_needed = true - end - - -- Reparse sections - Node.parse(self, true) + self.uci:commit(config) + -- Refresh data because commit changes section names + self.uci:load(config) end - 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()) + self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") + if self.apply_on_parse then + self.uci:apply(self.parsechain) + self:_run_hooks("on_apply", "on_after_apply") + else + -- This is evaluated by the dispatcher and delegated to the + -- template which in turn fires XHR to perform the actual + -- apply actions. + self.apply_needed = true end + + -- Reparse sections + 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(self:submitstate()) end - if self:submitstate() then - if not self.save then - self.state = FORM_INVALID - elseif self.proceed then - self.state = FORM_PROCEED - else - self.state = self.changed and FORM_CHANGED or FORM_VALID - end + if self.proceed then + self.state = FORM_PROCEED + elseif self.changed then + self.state = FORM_CHANGED else - self.state = FORM_NODATA + self.state = FORM_VALID end return self:state_handler(self.state) @@ -1470,6 +1471,7 @@ function Value.__init__(self, ...) self.template = "cbi/value" self.keylist = {} self.vallist = {} + self.readonly = nil end function Value.reset_values(self) @@ -1483,6 +1485,10 @@ function Value.value(self, key, val) table.insert(self.vallist, tostring(val)) end +function Value.parse(self, section, novld) + if self.readonly then return end + AbstractValue.parse(self, section, novld) +end -- DummyValue - This does nothing except being there DummyValue = class(AbstractValue) @@ -1527,26 +1533,39 @@ function Flag.__init__(self, ...) end -- A flag can only have two states: set or unset -function Flag.parse(self, section) +function Flag.parse(self, section, novld) local fexists = self.map:formvalue( FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option) if fexists then local fvalue = self:formvalue(section) and self.enabled or self.disabled - if fvalue ~= self.default or (not self.optional and not self.rmempty) then - self:write(section, fvalue) - else + local cvalue = self:cfgvalue(section) + local val_err + fvalue, val_err = self:validate(fvalue, section) + if not fvalue then + if not novld then + self:add_error(section, "invalid", val_err) + end + return + end + if fvalue == self.default and (self.optional or self.rmempty) then self:remove(section) + else + self:write(section, fvalue) end + if (fvalue ~= cvalue) then self.section.changed = true end else self:remove(section) + self.section.changed = true end end function Flag.cfgvalue(self, section) return AbstractValue.cfgvalue(self, section) or self.default end - +function Flag.validate(self, value) + return value +end --[[ ListValue - A one-line value predefined in a list