summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2008-09-23 00:10:51 +0000
committerJo-Philipp Wich <jow@openwrt.org>2008-09-23 00:10:51 +0000
commit6b3985b6be52063c09f779b6bc509bf84eedc660 (patch)
treecada805afb670f7648932f8c0e3a31ffbf512108
parent225de062447d8e29d927b821b41913723f392379 (diff)
* luci/libs/cbi:
- implement file upload fields - change default enctype in forms to multipart/form-data - add upload template * luci/libs/web: - dispatch file uploads to cbi form fields * luci/i18n: - add german and english translations for file upload fields
-rw-r--r--i18n/english/luasrc/i18n/cbi.en.lua2
-rw-r--r--i18n/english/luasrc/i18n/cbi.en.xml2
-rw-r--r--i18n/german/luasrc/i18n/cbi.de.lua2
-rw-r--r--i18n/german/luasrc/i18n/cbi.de.xml2
-rw-r--r--libs/cbi/luasrc/cbi.lua42
-rw-r--r--libs/cbi/luasrc/view/cbi/header.htm2
-rw-r--r--libs/cbi/luasrc/view/cbi/upload.htm28
-rw-r--r--libs/web/luasrc/dispatcher.lua141
8 files changed, 178 insertions, 43 deletions
diff --git a/i18n/english/luasrc/i18n/cbi.en.lua b/i18n/english/luasrc/i18n/cbi.en.lua
index 42f93d4cc..14b184b9e 100644
--- a/i18n/english/luasrc/i18n/cbi.en.lua
+++ b/i18n/english/luasrc/i18n/cbi.en.lua
@@ -1,5 +1,6 @@
cbi_add = 'Add entry'
cbi_del = 'Remove entry'
+cbi_replace = 'Replace entry'
cbi_invalid = 'Invalid input value'
cbi_invalid_section = '<strong>Validation failed:</strong> Please check any input fields for mistakes.'
cbi_missing = 'This field is mandatory'
@@ -12,3 +13,4 @@ cbi_manual = '-- custom --'
cbi_select = '-- Please choose --'
cbi_gorel = 'Go to relevant configuration page'
cbi_applying = 'Applying changes'
+cbi_upload = 'Uploaded File'
diff --git a/i18n/english/luasrc/i18n/cbi.en.xml b/i18n/english/luasrc/i18n/cbi.en.xml
index 4766ad155..c4843b1e7 100644
--- a/i18n/english/luasrc/i18n/cbi.en.xml
+++ b/i18n/english/luasrc/i18n/cbi.en.xml
@@ -4,6 +4,7 @@
<i18n:msg xml:id="cbi_add">Add entry</i18n:msg>
<i18n:msg xml:id="cbi_del">Remove entry</i18n:msg>
+<i18n:msg xml:id="cbi_replace">Replace entry</i18n:msg>
<i18n:msg xml:id="cbi_invalid">Invalid input value</i18n:msg>
<i18n:msg xml:id="cbi_invalid_section"><strong>Validation failed:</strong> Please check any input fields for mistakes.</i18n:msg>
<i18n:msg xml:id="cbi_missing">This field is mandatory</i18n:msg>
@@ -16,5 +17,6 @@
<i18n:msg xml:id="cbi_select">-- Please choose --</i18n:msg>
<i18n:msg xml:id="cbi_gorel">Go to relevant configuration page</i18n:msg>
<i18n:msg xml:id="cbi_applying">Applying changes</i18n:msg>
+<i18n:msg xml:id="cbi_upload">Uploaded File</i18n:msg>
</i18n:msgs>
diff --git a/i18n/german/luasrc/i18n/cbi.de.lua b/i18n/german/luasrc/i18n/cbi.de.lua
index 9e6907537..499805c6a 100644
--- a/i18n/german/luasrc/i18n/cbi.de.lua
+++ b/i18n/german/luasrc/i18n/cbi.de.lua
@@ -1,5 +1,6 @@
cbi_add = 'Eintrag hinzufügen'
cbi_del = 'Eintrag entfernen'
+cbi_replace = 'Eintrag ersetzen'
cbi_invalid = 'Ungültige Eingabe'
cbi_invalid_section = '<strong>Validierung fehlgeschlagen:</strong> Bitte die Eingabefelder auf Fehler überprüfen.'
cbi_missing = 'Dieses Feld muss ausgefüllt werden'
@@ -11,3 +12,4 @@ cbi_manual = '-- benutzerdefiniert --'
cbi_select = '-- Bitte auswählen --'
cbi_gorel = 'Gehe zu relevanter Konfigurationsseite'
cbi_applying = 'Änderungen werden angewandt'
+cbi_upload = 'hochgeladene Datei'
diff --git a/i18n/german/luasrc/i18n/cbi.de.xml b/i18n/german/luasrc/i18n/cbi.de.xml
index c989f8d8d..ab442aeaf 100644
--- a/i18n/german/luasrc/i18n/cbi.de.xml
+++ b/i18n/german/luasrc/i18n/cbi.de.xml
@@ -4,6 +4,7 @@
<i18n:msg xml:id="cbi_add">Eintrag hinzufügen</i18n:msg>
<i18n:msg xml:id="cbi_del">Eintrag entfernen</i18n:msg>
+<i18n:msg xml:id="cbi_replace">Eintrag ersetzen</i18n:msg>
<i18n:msg xml:id="cbi_invalid">Ungültige Eingabe</i18n:msg>
<i18n:msg xml:id="cbi_invalid_section"><strong>Validierung fehlgeschlagen:</strong> Bitte die Eingabefelder auf Fehler überprüfen.</i18n:msg>
<i18n:msg xml:id="cbi_missing">Dieses Feld muss ausgefüllt werden</i18n:msg>
@@ -15,5 +16,6 @@
<i18n:msg xml:id="cbi_select">-- Bitte auswählen --</i18n:msg>
<i18n:msg xml:id="cbi_gorel">Gehe zu relevanter Konfigurationsseite</i18n:msg>
<i18n:msg xml:id="cbi_applying">Änderungen werden angewandt</i18n:msg>
+<i18n:msg xml:id="cbi_upload">hochgeladene Datei</i18n:msg>
</i18n:msgs>
diff --git a/libs/cbi/luasrc/cbi.lua b/libs/cbi/luasrc/cbi.lua
index 97c453cf2..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
@@ -1328,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
diff --git a/libs/cbi/luasrc/view/cbi/header.htm b/libs/cbi/luasrc/view/cbi/header.htm
index ce5d66d77..3f60baf52 100644
--- a/libs/cbi/luasrc/view/cbi/header.htm
+++ b/libs/cbi/luasrc/view/cbi/header.htm
@@ -14,7 +14,7 @@ $Id$
-%>
<%+header%>
-<form method="post" action="<%=luci.http.getenv("REQUEST_URI")%>">
+<form method="post" action="<%=luci.http.getenv("REQUEST_URI")%>" enctype="multipart/form-data">
<div>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<input type="hidden" name="cbi.submit" value="1" />
diff --git a/libs/cbi/luasrc/view/cbi/upload.htm b/libs/cbi/luasrc/view/cbi/upload.htm
new file mode 100644
index 000000000..7e0ab1b50
--- /dev/null
+++ b/libs/cbi/luasrc/view/cbi/upload.htm
@@ -0,0 +1,28 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+
+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
+
+$Id$
+
+-%>
+
+<%
+ local t = require("luci.tools.webadmin")
+ local v = self:cfgvalue(section)
+-%>
+<%+cbi/valueheader%>
+ <% if v then %>
+ <%:cbi_upload Uploaded File%> (<%=t.byte_format(luci.fs.stat(v).size or 0)%>)
+ <input type="hidden"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
+ <input type="image" value="<%:cbi_replace%>" name="cbi.rlf.<%=section .. "." .. self.option%>" alt="<%:cbi_replace%>" title="<%:cbi_replace%>" src="<%=resource%>/cbi/reload.gif" />
+ <% else %>
+ <input type="file"<%= attr("name", cbid) .. attr("id", cbid) %> />
+ <% end %>
+<%+cbi/valuefooter%>
diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua
index 8e8e19063..0665ce42b 100644
--- a/libs/web/luasrc/dispatcher.lua
+++ b/libs/web/luasrc/dispatcher.lua
@@ -82,17 +82,17 @@ end
function authenticator.htmlauth(validator, accs, default)
local user = luci.http.formvalue("username")
local pass = luci.http.formvalue("password")
-
+
if user and validator(user, pass) then
return user
end
-
+
require("luci.i18n")
require("luci.template")
context.path = {}
luci.template.render("sysauth", {duser=default, fuser=user})
return false
-
+
end
--- Dispatch an HTTP request.
@@ -110,7 +110,7 @@ function httpdispatch(request)
if not stat then
error500(err)
end
-
+
luci.http.close()
--context._disable_memtrace()
@@ -122,15 +122,15 @@ function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace()
local ctx = context
ctx.path = request
-
+
require "luci.i18n".setlanguage(require "luci.config".main.lang)
-
+
local c = ctx.tree
local stat
if not c then
c = createtree()
end
-
+
local track = {}
local args = {}
context.args = args
@@ -144,7 +144,7 @@ function dispatch(request)
end
util.update(track, c)
-
+
if c.leaf then
break
end
@@ -159,7 +159,7 @@ function dispatch(request)
if track.i18n then
require("luci.i18n").loadc(track.i18n)
end
-
+
-- Init template engine
if not track.notemplate then
local tpl = require("luci.template")
@@ -174,23 +174,23 @@ function dispatch(request)
viewns.resource = luci.config.main.resourcebase
viewns.REQUEST_URI = (luci.http.getenv("SCRIPT_NAME") or "") .. (luci.http.getenv("PATH_INFO") or "")
end
-
+
track.dependent = (track.dependent ~= false)
assert(not track.dependent or not track.auto, "Access Violation")
-
+
if track.sysauth then
local sauth = require "luci.sauth"
-
+
local authen = type(track.sysauth_authenticator) == "function"
and track.sysauth_authenticator
or authenticator[track.sysauth_authenticator]
-
+
local def = (type(track.sysauth) == "string") and track.sysauth
local accs = def and {track.sysauth} or track.sysauth
local sess = ctx.authsession or luci.http.getcookie("sysauth")
sess = sess and sess:match("^[A-F0-9]+$")
local user = sauth.read(sess)
-
+
if not util.contains(accs, user) then
if authen then
local user, sess = authen(luci.sys.user.checkpasswd, accs, def)
@@ -221,19 +221,19 @@ function dispatch(request)
if c and type(c.target) == "function" then
context.dispatched = c
-
+
util.copcall(function()
local oldenv = getfenv(c.target)
local module = require(c.module)
local env = setmetatable({}, {__index=
-
+
function(tbl, key)
- return rawget(tbl, key) or module[key] or oldenv[key]
+ return rawget(tbl, key) or module[key] or oldenv[key]
end})
setfenv(c.target, env)
end)
-
+
c.target(unpack(args))
else
error404()
@@ -244,7 +244,7 @@ end
function createindex()
local path = luci.util.libpath() .. "/controller/"
local suff = ".lua"
-
+
if luci.util.copcall(require, "luci.fastindex") then
createindex_fastindex(path, suff)
else
@@ -257,14 +257,14 @@ end
-- @param suffix Controller file suffix
function createindex_fastindex(path, suffix)
index = {}
-
+
if not fi then
fi = luci.fastindex.new("index")
fi.add(path .. "*" .. suffix)
fi.add(path .. "*/*" .. suffix)
end
fi.scan()
-
+
for k, v in pairs(fi.indexes) do
index[v[2]] = v[1]
end
@@ -286,9 +286,9 @@ function createindex_plain(path, suffix)
index = loadfile(indexcache)()
return index
- end
+ end
end
-
+
index = {}
local controllers = util.combine(
@@ -300,12 +300,12 @@ function createindex_plain(path, suffix)
local module = "luci.controller." .. c:sub(#path+1, #c-#suffix):gsub("/", ".")
local mod = require(module)
local idx = mod.index
-
+
if type(idx) == "function" then
index[module] = idx
end
end
-
+
if indexcache then
fs.writefile(indexcache, util.get_bytecode(index))
fs.chmod(indexcache, "a-rwx,u+rw")
@@ -318,16 +318,16 @@ function createtree()
if not index then
createindex()
end
-
+
local ctx = context
local tree = {nodes={}}
-
+
ctx.treecache = setmetatable({}, {__mode="v"})
ctx.tree = tree
-
+
-- Load default translation
require "luci.i18n".loadc("default")
-
+
local scope = setmetatable({}, {__index = luci.dispatcher})
for k, v in pairs(index) do
@@ -335,7 +335,7 @@ function createtree()
setfenv(v, scope)
v()
end
-
+
return tree
end
@@ -349,24 +349,24 @@ function assign(path, clone, title, order)
local obj = node(unpack(path))
obj.nodes = nil
obj.module = nil
-
+
obj.title = title
obj.order = order
setmetatable(obj, {__index = _create_node(clone)})
-
+
return obj
end
--- Create a new dispatching node and define common parameters.
-- @param path Virtual path
--- @param target Target function to call when dispatched.
+-- @param target Target function to call when dispatched.
-- @param title Destination node title
-- @param order Destination node order value (optional)
-- @return Dispatching tree node
function entry(path, target, title, order)
local c = node(unpack(path))
-
+
c.target = target
c.title = title
c.order = order
@@ -392,19 +392,19 @@ function _create_node(path, cache)
if #path == 0 then
return context.tree
end
-
+
cache = cache or context.treecache
local name = table.concat(path, ".")
local c = cache[name]
-
+
if not c then
local last = table.remove(path)
c = _create_node(path, cache)
-
+
local new = {nodes={}, auto=true}
c.nodes[last] = new
cache[name] = new
-
+
return new
else
return c
@@ -428,20 +428,20 @@ end
function rewrite(n, ...)
local req = arg
return function()
- for i=1,n do
+ for i=1,n do
table.remove(context.path, 1)
end
-
+
for i,r in ipairs(req) do
table.insert(context.path, i, r)
end
-
+
dispatch()
end
end
--- Create a function-call dispatching target.
--- @param name Target function of local controller
+-- @param name Target function of local controller
-- @param ... Additional parameters passed to the function
function call(name, ...)
local argv = {...}
@@ -466,6 +466,63 @@ function cbi(model)
maps = luci.cbi.load(model, ...)
+ local uploads = { }
+ local has_upload = false
+
+ for _, map in ipairs(maps) do
+ 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
+
+ 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 = "/lib/uci/upload/"..field.name
+ fd = io.open(path, "w")
+ if fd then
+ cbid = field.name
+ prm[cbid] = path
+ -- else
+ -- io.stderr:write("E: " .. err .. "\n")
+ 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
+
for i, res in ipairs(maps) do
res:parse()
end