From 026ac8d033f4c0a65b0c8d121d1a2a86b2bd1ee1 Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Sun, 7 Feb 2016 09:30:29 +0100 Subject: [PATCH] luci-app-radicale: bump to version 1.1.0 - support Radicale > v1.1 - modified version detection - adaption to new function version_compare() in ipkg.lua - adaption to fixed Flag.parse() in cbi.lua - adaption to new property map.tabbed in cbi.lua using map template with extensions - change optional values to non optional - add support new option "system.boot_delay" Signed-off-by: Christian Schoenebeck --- applications/luci-app-radicale/Makefile | 4 +- .../luasrc/controller/radicale.lua | 298 +++++++++++--------- .../luasrc/model/cbi/radicale.lua | 306 ++++++++++----------- .../luasrc/view/radicale/btn_startstop.htm | 6 +- .../luasrc/view/radicale/ro_value.htm | 35 --- .../luasrc/view/radicale/tabmap_nsections.htm | 49 ++++ applications/luci-app-radicale/po/de/radicale.po | 50 +++- applications/luci-app-radicale/po/sv/radicale.po | 43 ++- .../luci-app-radicale/po/templates/radicale.pot | 29 +- 9 files changed, 482 insertions(+), 338 deletions(-) delete mode 100644 applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm create mode 100644 applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm diff --git a/applications/luci-app-radicale/Makefile b/applications/luci-app-radicale/Makefile index c403ba54d..2b969ace5 100644 --- a/applications/luci-app-radicale/Makefile +++ b/applications/luci-app-radicale/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2008-2015 The LuCI Team +# Copyright (C) 2008-2016 The LuCI Team # # This is free software, licensed under the Apache License, Version 2.0 . # @@ -10,7 +10,7 @@ PKG_NAME:=luci-app-radicale # Version == major.minor.patch # increase "minor" on new functionality and "patch" on patches/optimization -PKG_VERSION:=1.0.2 +PKG_VERSION:=1.1.0 # Release == build # increase on changes of translation files diff --git a/applications/luci-app-radicale/luasrc/controller/radicale.lua b/applications/luci-app-radicale/luasrc/controller/radicale.lua index 10ec1fe54..0be433a48 100644 --- a/applications/luci-app-radicale/luasrc/controller/radicale.lua +++ b/applications/luci-app-radicale/luasrc/controller/radicale.lua @@ -1,15 +1,23 @@ --- Copyright 2014 Christian Schoenebeck +-- Copyright 2014-2016 Christian Schoenebeck -- Licensed under the Apache License, Version 2.0 module("luci.controller.radicale", package.seeall) -local NX = require("nixio") -local NXFS = require("nixio.fs") -local DISP = require "luci.dispatcher" -local HTTP = require("luci.http") +local NX = require("nixio") +local NXFS = require("nixio.fs") +local DISP = require("luci.dispatcher") +local HTTP = require("luci.http") local I18N = require("luci.i18n") -- not globally avalible here -local UTIL = require("luci.util") -local SYS = require("luci.sys") +local IPKG = require("luci.model.ipkg") +local UTIL = require("luci.util") +local SYS = require("luci.sys") + +local srv_name = "radicale" +local srv_ver_min = "1.1" -- minimum version of service required +local srv_ver_cmd = [[/usr/bin/radicale --version]] +local app_name = "luci-app-radicale" +local app_title = I18N.translate("Radicale CalDAV/CardDAV Server") +local app_version = "1.1.0-1" function index() entry( {"admin", "services", "radicale"}, alias("admin", "services", "radicale", "edit"), _("CalDAV/CardDAV"), 58) @@ -19,6 +27,75 @@ function index() entry( {"admin", "services", "radicale", "status"}, call("_status") ).leaf = true end +-- Application / Service specific information functions +function app_description() + return I18N.translate("The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) server solution.") .. [[
]] + .. I18N.translate("Calendars and address books are available for both local and remote access, possibly limited through authentication policies.") .. [[
]] + .. I18N.translate("They can be viewed and edited by calendar and contact clients on mobile phones or computers.") +end +function app_title_main() + return [[]] + .. I18N.translate(app_title) + .. [[]] +end +function app_title_back() + return [[]] + .. I18N.translate(app_title) + .. [[]] +end +function app_err_value() + if not service_version() then + return [[


    ]] + .. I18N.translate("Software package '%s' is not installed." % srv_name) + .. [[

      ]] + .. I18N.translate("required") .. [[: ]] .. srv_name .. [[ ]] .. srv_ver_min + .. [[

    ]] + .. [[]] + .. I18N.translate("Please install current version !") + .. [[
 

]] + else + return [[


    ]] + .. I18N.translate("Software package '%s' is outdated." % srv_name) + .. [[

      ]] + .. I18N.translate("installed") .. [[: ]] .. srv_name .. [[ ]] .. service_version() + .. [[
      ]] + .. I18N.translate("required") .. [[: ]] .. srv_name .. [[ ]] .. srv_ver_min + .. [[

    ]] + .. [[]] + .. I18N.translate("Please update to current version !") + .. [[
 

]] + end +end + +function service_version() + local ver = nil + IPKG.list_installed(srv_name, function(n, v, d) + if v and (#v > 0) then ver = v end + end + ) + if not ver or (#ver == 0) then + ver = UTIL.exec(srv_ver_cmd) + if #ver == 0 then ver = nil end + end + return ver +end +function service_ok() + return IPKG.compare_versions((service_version() or "0"), ">=", srv_ver_min) +end + -- called by XHR.get from detail_logview.htm function _logread() -- read application settings @@ -60,138 +137,103 @@ function _status() HTTP.write(tostring(pid)) -- HTTP needs string not number end --- Application / Service specific information functions ######################## -function luci_app_name() - return "luci-app-radicale" -end - -function service_name() - return "radicale" -end -function service_required() - return "0.10-1" -end -function service_installed() - local v = ipkg_ver_installed("radicale-py2") - if not v or #v == 0 then v = ipkg_ver_installed("radicale-py3") end - if not v or #v == 0 then v = "0" end - return v -end -function service_ok() - return ipkg_ver_compare(service_installed(),">=",service_required()) -end - -function app_title_main() - return [[]] - .. I18N.translate("Radicale CalDAV/CardDAV Server") - .. [[]] -end -function app_title_back() - return [[]] - .. I18N.translate("Radicale CalDAV/CardDAV Server") - .. [[]] -end -function app_description() - return I18N.translate("The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) server solution.") .. [[
]] - .. I18N.translate("Calendars and address books are available for both local and remote access, possibly limited through authentication policies.") .. [[
]] - .. I18N.translate("They can be viewed and edited by calendar and contact clients on mobile phones or computers.") -end - --- other multiused functions ################################################### - --return pid of running process function get_pid() return tonumber(SYS.exec([[ps | grep "[p]ython.*[r]adicale" 2>/dev/null | awk '{print $1}']])) or 0 end --- compare versions using "<=" "<" ">" ">=" "=" "<<" ">>" -function ipkg_ver_compare(ver1, comp, ver2) - if not ver1 or not ver2 - or not comp or not (#comp > 0) then return nil end - -- correct compare string - if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~=" - elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<=" - elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">=" - elseif comp == "=" or comp == "==" then comp = "==" - elseif comp == "<<" then comp = "<" - elseif comp == ">>" then comp = ">" - else return nil end - - local av1 = UTIL.split(ver1, "[%.%-]", nil, true) - local av2 = UTIL.split(ver2, "[%.%-]", nil, true) - - for i = 1, math.max(table.getn(av1),table.getn(av2)), 1 do - local s1 = av1[i] or "" - local s2 = av2[i] or "" - - -- first "not equal" found return true - if comp == "~=" and (s1 ~= s2) then return true end - -- first "lower" found return true - if (comp == "<" or comp == "<=") and (s1 < s2) then return true end - -- first "greater" found return true - if (comp == ">" or comp == ">=") and (s1 > s2) then return true end - -- not equal then return false - if (s1 ~= s2) then return false end +-- replacement of build-in parse of "Value" +-- modified AbstractValue.parse(self, section, novld) from cbi.lua +-- validate is called if rmempty/optional true or false +-- before write check if forcewrite, value eq default, and more +function value_parse(self, section, novld) + local fvalue = self:formvalue(section) + local fexist = ( fvalue and (#fvalue > 0) ) -- not "nil" and "not empty" + local cvalue = self:cfgvalue(section) + local rm_opt = ( self.rmempty or self.optional ) + local eq_cfg -- flag: equal cfgvalue + + -- If favlue and cvalue are both tables and have the same content + -- make them identical + if type(fvalue) == "table" and type(cvalue) == "table" then + eq_cfg = (#fvalue == #cvalue) + if eq_cfg then + for i=1, #fvalue do + if cvalue[i] ~= fvalue[i] then + eq_cfg = false + end + end + end + if eq_cfg then + fvalue = cvalue + end end - -- all equal and not compare greater or lower then true - return not (comp == "<" or comp == ">") -end + -- removed parameter "section" from function call because used/accepted nowhere + -- also removed call to function "transfer" + local vvalue, errtxt = self:validate(fvalue) --- read version information for given package if installed -function ipkg_ver_installed(pkg) - local version = "" - local control = io.open("/usr/lib/opkg/info/%s.control" % pkg, "r") - if control then - local ln - repeat - ln = control:read("*l") - if ln and ln:match("^Version: ") then - version = ln:gsub("^Version: ", "") - break - end - until not ln - control:close() + -- error handling; validate return "nil" + if not vvalue then + if novld then -- and "novld" set + return -- then exit without raising an error + end + + if fexist then -- and there is a formvalue + self:add_error(section, "invalid", errtxt) + return -- so data are invalid + elseif not rm_opt then -- and empty formvalue but NOT (rmempty or optional) set + self:add_error(section, "missing", errtxt) + return -- so data is missing + elseif errtxt then + self:add_error(section, "invalid", errtxt) + return + end +-- error ("\n option: " .. self.option .. +-- "\n fvalue: " .. tostring(fvalue) .. +-- "\n fexist: " .. tostring(fexist) .. +-- "\n cvalue: " .. tostring(cvalue) .. +-- "\n vvalue: " .. tostring(vvalue) .. +-- "\n vexist: " .. tostring(vexist) .. +-- "\n rm_opt: " .. tostring(rm_opt) .. +-- "\n eq_cfg: " .. tostring(eq_cfg) .. +-- "\n eq_def: " .. tostring(eq_def) .. +-- "\n novld : " .. tostring(novld) .. +-- "\n errtxt: " .. tostring(errtxt) ) end - return version -end --- replacement of build-in Flag.parse of cbi.lua --- modified to mark section as changed if value changes --- current parse did not do this, but it is done AbstaractValue.parse() -function flag_parse(self, section) - local fexists = self.map:formvalue( - luci.cbi.FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option) - - if fexists then - local fvalue = self:formvalue(section) and self.enabled or self.disabled - local cvalue = self:cfgvalue(section) - if fvalue ~= self.default or (not self.optional and not self.rmempty) then - self:write(section, fvalue) - else - self:remove(section) + -- lets continue with value returned from validate + eq_cfg = ( vvalue == cvalue ) -- update equal_config flag + local vexist = ( vvalue and (#vvalue > 0) ) and true or false -- not "nil" and "not empty" + local eq_def = ( vvalue == self.default ) -- equal_default flag + + -- (rmempty or optional) and (no data or equal_default) + if rm_opt and (not vexist or eq_def) then + if self:remove(section) then -- remove data from UCI + self.section.changed = true -- and push events end - if (fvalue ~= cvalue) then self.section.changed = true end - else - self:remove(section) + return + end + + -- not forcewrite and no changes, so nothing to write + if not self.forcewrite and eq_cfg then + return + end + + -- we should have a valid value here + assert (vvalue, "\n option: " .. self.option .. + "\n fvalue: " .. tostring(fvalue) .. + "\n fexist: " .. tostring(fexist) .. + "\n cvalue: " .. tostring(cvalue) .. + "\n vvalue: " .. tostring(vvalue) .. + "\n vexist: " .. tostring(vexist) .. + "\n rm_opt: " .. tostring(rm_opt) .. + "\n eq_cfg: " .. tostring(eq_cfg) .. + "\n eq_def: " .. tostring(eq_def) .. + "\n errtxt: " .. tostring(errtxt) ) + + -- write data to UCI; raise event only on changes + if self:write(section, vvalue) and not eq_cfg then self.section.changed = true end end diff --git a/applications/luci-app-radicale/luasrc/model/cbi/radicale.lua b/applications/luci-app-radicale/luasrc/model/cbi/radicale.lua index 8abb68869..c610478bc 100644 --- a/applications/luci-app-radicale/luasrc/model/cbi/radicale.lua +++ b/applications/luci-app-radicale/luasrc/model/cbi/radicale.lua @@ -1,14 +1,43 @@ --- Copyright 2015 Christian Schoenebeck +-- Copyright 2015-2016 Christian Schoenebeck -- Licensed under the Apache License, Version 2.0 -local NXFS = require("nixio.fs") -local DISP = require("luci.dispatcher") -local DTYP = require("luci.cbi.datatypes") -local HTTP = require("luci.http") -local UTIL = require("luci.util") -local UCI = require("luci.model.uci") -local SYS = require("luci.sys") -local TOOLS = require("luci.controller.radicale") -- this application's controller and multiused functions +local NXFS = require("nixio.fs") +local DISP = require("luci.dispatcher") +local DTYP = require("luci.cbi.datatypes") +local HTTP = require("luci.http") +local UTIL = require("luci.util") +local UCI = require("luci.model.uci") +local SYS = require("luci.sys") +local WADM = require("luci.tools.webadmin") +local CTRL = require("luci.controller.radicale") -- this application's controller and multiused functions + +-- ################################################################################################# +-- Error handling if not installed or wrong version -- ######################### +if not CTRL.service_ok() then + local f = SimpleForm("__sf") + f.title = CTRL.app_title_main() + f.description = CTRL.app_description() + f.embedded = true + f.submit = false + f.reset = false + + local s = f:section(SimpleSection) + s.title = [[]] .. [[]] + .. translate("Software update required") + .. [[]] .. [[]] + + local v = s:option(DummyValue, "_dv") + v.rawhtml = true + v.value = CTRL.app_err_value + + return f +end + +-- ################################################################################################# +-- Error handling if no config, create an empty one -- ######################### +if not NXFS.access("/etc/config/radicale") then + NXFS.writefile("/etc/config/radicale", "") +end -- ################################################################################################# -- takeover arguments if any -- ################################################ @@ -19,8 +48,8 @@ if arg[1] then -- SimpleForm ------------------------------------------------ local ft = SimpleForm("_text") - ft.title = TOOLS.app_title_back() - ft.description = TOOLS.app_description() + ft.title = CTRL.app_title_back() + ft.description = CTRL.app_description() ft.redirect = DISP.build_url("admin", "services", "radicale") .. "#cbi-radicale-" .. argument if argument == "logger" then ft.reset = false @@ -95,54 +124,12 @@ if arg[1] then end --- ################################################################################################# --- Error handling if not installed or wrong version -- ######################### -if not TOOLS.service_ok() then - local f = SimpleForm("_no_config") - f.title = TOOLS.app_title_main() - f.description = TOOLS.app_description() - f.submit = false - f.reset = false - - local s = f:section(SimpleSection) - - local v = s:option(DummyValue, "_update_needed") - v.rawhtml = true - if TOOLS.service_installed() == "0" then - v.value = [[


    ]] - .. translate("Software package '" .. TOOLS.service_name() .. "' is not installed.") - .. [[

      ]] - .. translate("required") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_required() - .. [[

    ]] - .. [[]] - .. translate("Please install current version !") - .. [[
 

]] - else - v.value = [[


    ]] - .. translate("Software package '" .. TOOLS.service_name() .. "' is outdated.") - .. [[

      ]] - .. translate("installed") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_installed() - .. [[
      ]] - .. translate("required") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_required() - .. [[

    ]] - .. [[]] - .. translate("Please update to current version !") - .. [[
 

]] - end - - return f -end - --- ################################################################################################# --- Error handling if no config, create an empty one -- ######################### -if not NXFS.access("/etc/config/radicale") then - NXFS.writefile("/etc/config/radicale", "") -end - -- cbi-map -- ################################################################## local m = Map("radicale") -m.title = TOOLS.app_title_main() -m.description = TOOLS.app_description() +m.title = CTRL.app_title_main() +m.description = CTRL.app_description() +m.template = "radicale/tabmap_nsections" +m.tabbed = true function m.commit_handler(self) if self.changed then -- changes ? os.execute("/etc/init.d/radicale reload &") -- reload configuration @@ -150,11 +137,14 @@ function m.commit_handler(self) end -- cbi-section "System" -- ##################################################### -local sys = m:section( NamedSection, "_system" ) +local sys = m:section( NamedSection, "system", "system" ) sys.title = translate("System") sys.description = nil function sys.cfgvalue(self, section) - return "_dummysection" + if not self.map:get(section) then -- section might not exist + self.map:set(section, nil, self.sectiontype) + end + return self.map:get(section) end -- start/stop button ----------------------------------------------------------- @@ -165,7 +155,7 @@ btn.rmempty = true btn.title = translate("Start / Stop") btn.description = translate("Start/Stop Radicale server") function btn.cfgvalue(self, section) - local pid = TOOLS.get_pid(true) + local pid = CTRL.get_pid(true) if pid > 0 then btn.inputtitle = "PID: " .. pid btn.inputstyle = "reset" @@ -183,18 +173,39 @@ local ena = sys:option(Flag, "_enabled") ena.title = translate("Auto-start") ena.description = translate("Enable/Disable auto-start of Radicale on system start-up and interface events") ena.orientation = "horizontal" -- put description under the checkbox -ena.rmempty = false -- we need write +ena.rmempty = false -- force write() function function ena.cfgvalue(self, section) - return (SYS.init.enabled("radicale")) and "1" or "0" + return (SYS.init.enabled("radicale")) and self.enabled or self.disabled end function ena.write(self, section, value) - if value == "1" then + if value == self.enabled then return SYS.init.enable("radicale") else return SYS.init.disable("radicale") end end +-- boot_delay ------------------------------------------------------------------ +local bd = sys:option(Value, "boot_delay") +bd.title = translate("Boot delay") +bd.description = translate("Delay (in seconds) during system boot before Radicale start") + .. [[
]] + .. translate("During delay ifup-events are not monitored !") +bd.default = "10" +function bd.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end +function bd.validate(self, value) + local val = tonumber(value) + if not val then + return nil, self.title .. ": " .. translate("Value is not a number") + elseif val < 0 or val > 300 then + return nil, self.title .. ": " .. translate("Value not between 0 and 300") + end + return value +end + + -- cbi-section "Server" -- ##################################################### local srv = m:section( NamedSection, "server", "setting" ) srv.title = translate("Server") @@ -215,15 +226,17 @@ sh.description = translate("'Hostname:Port' or 'IPv4:Port' or '[IPv6]:Port' Radi .. [[]] sh.placeholder = "0.0.0.0:5232" sh.rmempty = true +function sh.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- realm ----------------------------------------------------------------------- local alm = srv:option( Value, "realm" ) alm.title = translate("Logon message") alm.description = translate("Message displayed in the client when a password is needed.") alm.default = "Radicale - Password Required" -alm.rmempty = false -function alm.parse(self, section) - AbstractValue.parse(self, section, "true") -- otherwise unspecific validate error +function alm.parse(self, section, novld) + CTRL.value_parse(self, section, novld) end function alm.validate(self, value) if value then @@ -232,22 +245,11 @@ function alm.validate(self, value) return self.default end end -function alm.write(self, section, value) - if value ~= self.default then - return self.map:set(section, self.option, value) - else - return self.map:del(section, self.option) - end -end -- ssl ------------------------------------------------------------------------- local ssl = srv:option( Flag, "ssl" ) ssl.title = translate("Enable HTTPS") ssl.description = nil -ssl.rmempty = false -function ssl.parse(self, section) - TOOLS.flag_parse(self, section) -end function ssl.write(self, section, value) if value == "0" then -- delete all if not https enabled self.map:del(section, "protocol") -- protocol @@ -273,18 +275,18 @@ prt:value ("PROTOCOL_SSLv3", "SSL v3") prt:value ("PROTOCOL_TLSv1", "TLS v1") prt:value ("PROTOCOL_TLSv1_1", "TLS v1.1") prt:value ("PROTOCOL_TLSv1_2", "TLS v1.2") +function prt.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- certificate ----------------------------------------------------------------- local crt = srv:option( Value, "certificate" ) crt.title = translate("Certificate file") crt.description = translate("Full path and file name of certificate") crt.placeholder = "/etc/radicale/ssl/server.crt" -crt.rmempty = false -- force validate/write crt:depends ("ssl", "1") -function crt.parse(self, section) - local _ssl = ssl:formvalue(section) or "0" - local novld = (_ssl == "0") - AbstractValue.parse(self, section, novld) -- otherwise unspecific validate error +function crt.parse(self, section, novld) + CTRL.value_parse(self, section, novld) end function crt.validate(self, value) local _ssl = ssl:formvalue(srv.section) or "0" @@ -295,17 +297,10 @@ function crt.validate(self, value) if DTYP.file(value) then return value else - return nil, self.title .. " - " .. translate("File not found !") + return nil, self.title .. ": " .. translate("File not found !") end else - return nil, self.title .. " - " .. translate("Path/File required !") - end -end -function crt.write(self, section, value) - if not value or #value == 0 then - return self.map:del(section, self.option) - else - return self.map:set(section, self.option, value) + return nil, self.title .. ": " .. translate("Path/File required !") end end @@ -314,12 +309,9 @@ local key = srv:option( Value, "key" ) key.title = translate("Private key file") key.description = translate("Full path and file name of private key") key.placeholder = "/etc/radicale/ssl/server.key" -key.rmempty = false -- force validate/write key:depends ("ssl", "1") -function key.parse(self, section) - local _ssl = ssl:formvalue(section) or "0" - local novld = (_ssl == "0") - AbstractValue.parse(self, section, novld) -- otherwise unspecific validate error +function key.parse(self, section, novld) + CTRL.value_parse(self, section, novld) end function key.validate(self, value) local _ssl = ssl:formvalue(srv.section) or "0" @@ -330,17 +322,10 @@ function key.validate(self, value) if DTYP.file(value) then return value else - return nil, self.title .. " - " .. translate("File not found !") + return nil, self.title .. ": " .. translate("File not found !") end else - return nil, self.title .. " - " .. translate("Path/File required !") - end -end -function key.write(self, section, value) - if not value or #value == 0 then - return self.map:del(section, self.option) - else - return self.map:set(section, self.option, value) + return nil, self.title .. ": " .. translate("Path/File required !") end end @@ -377,6 +362,9 @@ aty:value ("htpasswd", translate("htpasswd file")) --aty:value ("HTTP", "HTTP") -- The HTTP authentication module relies on the requests module --aty:value ("remote_user", "remote_user") --aty:value ("custom", translate("custom")) +function aty.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function aty.write(self, section, value) if value ~= "htpasswd" then self.map:del(section, "htpasswd_encryption") @@ -403,9 +391,12 @@ hte:value ("crypt", translate("crypt")) hte:value ("plain", translate("plain")) hte:value ("sha1", translate("SHA-1")) hte:value ("ssha", translate("salted SHA-1")) +function hte.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- htpasswd_file (dummy) ------------------------------------------------------- -local htf = aut:option( DummyValue, "_htf" ) +local htf = aut:option( Value, "_htf" ) htf.title = translate("htpasswd file") htf.description = [[]] .. translate("Read only!") @@ -416,9 +407,6 @@ htf.description = [[]] .. [[">]] .. translate("To edit the file follow this link!") .. [[]] -htf.keylist = {} -- required by template -htf.vallist = {} -- required by template -htf.template = "radicale/ro_value" htf.readonly = true htf:depends ("type", "htpasswd") function htf.cfgvalue() @@ -448,6 +436,9 @@ rty:value ("owner_only", translate("Full access for Owner only") ) rty:value ("owner_write", translate("Owner allow write, authenticated users allow read") ) rty:value ("from_file", translate("Rights are based on a regexp-based file") ) --rty:value ("custom", "Custom handler") +function rty.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function rty.write(self, section, value) if value ~= "custom" then self.map:del(section, "custom_handler") @@ -460,7 +451,7 @@ function rty.write(self, section, value) end -- from_file (dummy) ----------------------------------------------------------- -local rtf = rig:option( DummyValue, "_rtf" ) +local rtf = rig:option( Value, "_rtf" ) rtf.title = translate("RegExp file") rtf.description = [[]] .. translate("Read only!") @@ -471,9 +462,6 @@ rtf.description = [[]] .. [[">]] .. translate("To edit the file follow this link!") .. [[]] -rtf.keylist = {} -- required by template -rtf.vallist = {} -- required by template -rtf.template = "radicale/ro_value" rtf.readonly = true rtf:depends ("type", "from_file") function rtf.cfgvalue() @@ -501,6 +489,9 @@ sty:value ("filesystem", translate("File-system")) --sty:value ("multifilesystem", translate("") ) --sty:value ("database", translate("Database") ) --sty:value ("custom", translate("Custom") ) +function sty.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function sty.write(self, section, value) if value ~= "filesystem" then self.map:del(section, "filesystem_folder") @@ -516,13 +507,10 @@ end local sfi = sto:option( Value, "filesystem_folder" ) sfi.title = translate("Directory") sfi.description = nil -sfi.default = "/srv/radicale" -sfi.rmempty = false -- force validate/write +sfi.placeholder = "/srv/radicale" sfi:depends ("type", "filesystem") -function sfi.parse(self, section) - local _typ = sty:formvalue(sto.section) or "" - local novld = (_typ ~= "filesystem") - AbstractValue.parse(self, section, novld) -- otherwise unspecific validate error +function sfi.parse(self, section, novld) + CTRL.value_parse(self, section, novld) end function sfi.validate(self, value) local _typ = sty:formvalue(sto.section) or "" @@ -533,10 +521,10 @@ function sfi.validate(self, value) if DTYP.directory(value) then return value else - return nil, self.title .. " - " .. translate("Directory not exists/found !") + return nil, self.title .. ": " .. translate("Directory not exists/found !") end else - return nil, self.title .. " - " .. translate("Directory required !") + return nil, self.title .. ": " .. translate("Directory required !") end end @@ -562,6 +550,9 @@ lco:value ("INFO", translate("Info") ) lco:value ("WARNING", translate("Warning") ) lco:value ("ERROR", translate("Error") ) lco:value ("CRITICAL", translate("Critical") ) +function lco.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function lco.write(self, section, value) if value ~= self.default then return self.map:set(section, self.option, value) @@ -581,6 +572,9 @@ lsl:value ("INFO", translate("Info") ) lsl:value ("WARNING", translate("Warning") ) lsl:value ("ERROR", translate("Error") ) lsl:value ("CRITICAL", translate("Critical") ) +function lsl.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function lsl.write(self, section, value) if value ~= self.default then return self.map:set(section, self.option, value) @@ -600,6 +594,9 @@ lfi:value ("INFO", translate("Info") ) lfi:value ("WARNING", translate("Warning") ) lfi:value ("ERROR", translate("Error") ) lfi:value ("CRITICAL", translate("Critical") ) +function lfi.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function lfi.write(self, section, value) if value ~= self.default then return self.map:set(section, self.option, value) @@ -618,12 +615,14 @@ lfp.description = translate("Directory where the rotating log-files are stored") .. translate("To view latest log file follow this link!") .. [[]] lfp.default = "/var/log/radicale" -function lfp.write(self, section, value) - if value ~= self.default then - return self.map:set(section, self.option, value) - else - return self.map:del(section, self.option) +function lfp.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end +function lfp.validate(self, value) + if not value or (#value < 1) or (value:find("/") ~= 1) then + return nil, self.title .. ": " .. translate("no valid path given!") end + return value end -- file_maxbytes --------------------------------------------------------------- @@ -634,23 +633,18 @@ lmb.description = translate("Maximum size of each rotation log-file.") .. translate("Setting this parameter to '0' will disable rotation of log-file.") .. [[]] lmb.default = "8196" -lmb.rmempty = false +function lmb.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function lmb.validate(self, value) if value then -- otherwise errors in datatype check if DTYP.uinteger(value) then return value else - return nil, self.title .. " - " .. translate("Value is not an Integer >= 0 !") + return nil, self.title .. ": " .. translate("Value is not an Integer >= 0 !") end else - return nil, self.title .. " - " .. translate("Value required ! Integer >= 0 !") - end -end -function lmb.write(self, section, value) - if value ~= self.default then - return self.map:set(section, self.option, value) - else - return self.map:del(section, self.option) + return nil, self.title .. ": " .. translate("Value required ! Integer >= 0 !") end end @@ -662,23 +656,18 @@ lbc.description = translate("Number of backup files of log to create.") .. translate("Setting this parameter to '0' will disable rotation of log-file.") .. [[]] lbc.default = "1" -lbc.rmempty = false +function lbc.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end function lbc.validate(self, value) if value then -- otherwise errors in datatype check if DTYP.uinteger(value) then return value else - return nil, self.title .. " - " .. translate("Value is not an Integer >= 0 !") + return nil, self.title .. ": " .. translate("Value is not an Integer >= 0 !") end else - return nil, self.title .. " - " .. translate("Value required ! Integer >= 0 !") - end -end -function lbc.write(self, section, value) - if value ~= self.default then - return self.map:set(section, self.option, value) - else - return self.map:del(section, self.option) + return nil, self.title .. ": " .. translate("Value required ! Integer >= 0 !") end end @@ -699,14 +688,18 @@ local enr = enc:option( Value, "request" ) enr.title = translate("Response Encoding") enr.description = translate("Encoding for responding requests.") enr.default = "utf-8" -enr.optional = true +function enr.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- stock ----------------------------------------------------------------------- local ens = enc:option( Value, "stock" ) ens.title = translate("Storage Encoding") ens.description = translate("Encoding for storing local collections.") ens.default = "utf-8" -ens.optional = true +function ens.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- cbi-section "Headers" -- #################################################### local hea = m:section( NamedSection, "headers", "setting" ) @@ -724,25 +717,32 @@ end local heo = hea:option( DynamicList, "Access_Control_Allow_Origin" ) heo.title = translate("Access-Control-Allow-Origin") heo.description = nil -heo.default = "*" -heo.optional = true +function heo.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- Access_Control_Allow_Methods ------------------------------------------------ local hem = hea:option( DynamicList, "Access_Control_Allow_Methods" ) hem.title = translate("Access-Control-Allow-Methods") hem.description = nil -hem.optional = true +function hem.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- Access_Control_Allow_Headers ------------------------------------------------ local heh = hea:option( DynamicList, "Access_Control_Allow_Headers" ) heh.title = translate("Access-Control-Allow-Headers") heh.description = nil -heh.optional = true +function heh.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end -- Access_Control_Expose_Headers ----------------------------------------------- local hee = hea:option( DynamicList, "Access_Control_Expose_Headers" ) hee.title = translate("Access-Control-Expose-Headers") hee.description = nil -hee.optional = true +function hee.parse(self, section, novld) + CTRL.value_parse(self, section, novld) +end return m diff --git a/applications/luci-app-radicale/luasrc/view/radicale/btn_startstop.htm b/applications/luci-app-radicale/luasrc/view/radicale/btn_startstop.htm index dbf4dddbc..d9ef82214 100644 --- a/applications/luci-app-radicale/luasrc/view/radicale/btn_startstop.htm +++ b/applications/luci-app-radicale/luasrc/view/radicale/btn_startstop.htm @@ -4,7 +4,7 @@ // show XHR.poll/XHR.get response on button function _data2elements(x) { - var btn = document.getElementById("cbid.radicale._system._startstop"); + var btn = document.getElementById("cbid.radicale.<%=section%>._startstop"); if ( ! btn ) { return; } // security check if (x.responseText == "0") { btn.value = "<%:Start%>"; @@ -21,12 +21,12 @@ function onclick_startstop(id) { // do start/stop var btnXHR = new XHR(); - btnXHR.post('<%=url('admin/services/radicale/startstop')%>', { token: '<%=token%>' }, + btnXHR.post('<%=url([[admin/services/radicale/startstop]])%>', { token: '<%=token%>' }, function(x) { _data2elements(x); } ); } - XHR.poll(5, '<%=url('admin/services/radicale/status')%>', null, + XHR.poll(5, '<%=url([[admin/services/radicale/status]])%>', null, function(x, data) { _data2elements(x); } ); diff --git a/applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm b/applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm deleted file mode 100644 index 6e05206aa..000000000 --- a/applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm +++ /dev/null @@ -1,35 +0,0 @@ -<%+cbi/valueheader%> - /> - <% if self.password then %><% end %> - <% if #self.keylist > 0 or self.datatype then -%> - - <% end -%> -<%+cbi/valuefooter%> diff --git a/applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm b/applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm new file mode 100644 index 000000000..45fe60cc8 --- /dev/null +++ b/applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm @@ -0,0 +1,49 @@ +<%- if firstmap and messages then local msg; for _, msg in ipairs(messages) do -%> +
<%=pcdata(msg)%>
+<%- end end -%> + +<%-+cbi/apply_xhr-%> + +
+ <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> + <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> + <%- if firstmap and applymap then cbi_apply_xhr(self.config, parsechain, redirect) end -%> + + <% if self.tabbed then %> +
    + <%- self.selected_tab = luci.http.formvalue("tab.m-" .. self.config) %> + <% for i, section in ipairs(self.children) do %> + <%- if not self.selected_tab then self.selected_tab = section.sectiontype end %> +
  • + <%=section.title or section.section or section.sectiontype %> + <% if section.sectiontype == self.selected_tab then %><% end %> +
  • + <% end %> +
+
+ <% for i, section in ipairs(self.children) do %> +
style="display:none"<% end %>> + <% section:render() %> +
+ + <% end %> + + <% else %> + <%- self:render_children() %> + <% end %> + + <% if not self.save then -%> +
+ <% for _, section in ipairs(self.children) do %> + <% if section.error and section.error[section.section] then -%> +
  • + <%:One or more missing/invalid fields on tab%>: <%=section.title or section.section or section.sectiontype%> +
+ <%- end %> + <% end %> +
+ <%- end %> + +
+ +
diff --git a/applications/luci-app-radicale/po/de/radicale.po b/applications/luci-app-radicale/po/de/radicale.po index 57850dc10..ef47988a4 100644 --- a/applications/luci-app-radicale/po/de/radicale.po +++ b/applications/luci-app-radicale/po/de/radicale.po @@ -1,15 +1,15 @@ msgid "" msgstr "" -"Project-Id-Version: luci-app-radicale\n" -"POT-Creation-Date: 2015-05-02 19:32+0100\n" -"PO-Revision-Date: 2015-05-02 22:43+0100\n" -"Last-Translator: Christian Schoenebeck \n" +"Project-Id-Version: luci-app-radicale 1.1.0-1\n" +"POT-Creation-Date: 2016-01-30 20:34+0100\n" +"PO-Revision-Date: 2016-01-31 20:49+0100\n" +"Last-Translator: Christian Schönebeck \n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.7.5\n" +"X-Generator: Poedit 1.8.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -72,6 +72,9 @@ msgstr "" msgid "Auto-start" msgstr "Autostart" +msgid "Boot delay" +msgstr "Systemstart-Verzögerung" + msgid "CalDAV/CardDAV" msgstr "CalDAV/CardDAV" @@ -122,6 +125,10 @@ msgstr "Datenbank" msgid "Debug" msgstr "Debug" +msgid "Delay (in seconds) during system boot before Radicale start" +msgstr "" +"Verzögerung (in Sekunden) während des Systemstarts, bevor Radicale startet" + msgid "Directory" msgstr "Verzeichnis" @@ -135,6 +142,9 @@ msgid "Directory where the rotating log-files are stored" msgstr "" "Verzeichnis in dem die rollierenden Protokolldateien gespeichert werden" +msgid "During delay ifup-events are not monitored !" +msgstr "Während der Verzögerung werden 'ifup'-Ereignisse nicht überwacht!" + msgid "Enable HTTPS" msgstr "Verwende HTTPS" @@ -240,6 +250,9 @@ msgstr "Anzahl der Protokoll Backup Dateien, die angelegt werden." msgid "OPTIONAL: See python's ssl module for available ciphers" msgstr "OPTIONAL: Siehe Python SSL-Modul Dokumentation" +msgid "One or more missing/invalid fields on tab" +msgstr "Ein oder mehrere fehlende/ungültige Felder auf der Registerkarte" + msgid "Owner allow write, authenticated users allow read" msgstr "" "Besitzer haben Schreibrechte, Authentifizierten Benutzer dürfen nur lesen." @@ -324,8 +337,14 @@ msgstr "" "Wenn dieser Parameter auf '0' gesetzt wird, wird die Protokolldatei nicht " "mehr rolliert!" -msgid "Software package '" -msgstr "Software Packet '" +msgid "Software package '%s' is not installed." +msgstr "Software Paket '%s' ist nicht installiert." + +msgid "Software package '%s' is outdated." +msgstr "Software Paket '%s' ist nicht aktuell." + +msgid "Software update required" +msgstr "Software-Update erforderlich" msgid "Start" msgstr "Start" @@ -372,9 +391,15 @@ msgid "To view latest log file follow this link!" msgstr "" "Zur Anzeige der letzten Protokolldatei, folgen Sie dieser Verknüpfung !" +msgid "Value is not a number" +msgstr "Wert ist keine Zahl" + msgid "Value is not an Integer >= 0 !" msgstr "Eingabe ist keine Ganzzahl >= 0 !" +msgid "Value not between 0 and 300" +msgstr "Wert nicht zwischen 0 und 300" + msgid "Value required ! Integer >= 0 !" msgstr "Eingabe erforderlich ! Ganzzahl >= 0 !" @@ -397,6 +422,8 @@ msgid "" "You can also get groups from the user regex in the collection with {0}, {1}, " "etc." msgstr "" +"Sie können auch Gruppen aus der Benutzer regex in der Sammlung mit {0}, {1} " +"usw. bekommen." msgid "" "You can use Python's ConfigParser interpolation values %(login)s and " @@ -416,6 +443,9 @@ msgstr "htpasswd Datei" msgid "installed" msgstr "installiert" +msgid "no valid path given!" +msgstr "Keine gültige Pfadangabe!" + msgid "or higher" msgstr "oder höher" @@ -427,9 +457,3 @@ msgstr "erforderlich" msgid "salted SHA-1" msgstr "Salted SHA-1" - -#~ msgid "File" -#~ msgstr "Datei" - -#~ msgid "not found !" -#~ msgstr "nicht gefunden !" diff --git a/applications/luci-app-radicale/po/sv/radicale.po b/applications/luci-app-radicale/po/sv/radicale.po index 3b141a2fe..cf899d83f 100644 --- a/applications/luci-app-radicale/po/sv/radicale.po +++ b/applications/luci-app-radicale/po/sv/radicale.po @@ -1,5 +1,15 @@ msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8\n" +msgstr "" +"Project-Id-Version: luci-app-radicale 1.1.0-1\n" +"POT-Creation-Date: 2016-01-30 20:34+0100\n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.4\n" msgid "" "'AUTO' selects the highest protocol version that client and server support." @@ -53,6 +63,9 @@ msgstr "Autentiseringsmetod för att tillåta åtkomst till Radicale-servern." msgid "Auto-start" msgstr "Starta automatiskt" +msgid "Boot delay" +msgstr "" + msgid "CalDAV/CardDAV" msgstr "CalDAV/CardDAV" @@ -98,6 +111,9 @@ msgstr "Databas" msgid "Debug" msgstr "Felsök" +msgid "Delay (in seconds) during system boot before Radicale start" +msgstr "" + msgid "Directory" msgstr "Mapp" @@ -110,6 +126,9 @@ msgstr "Mapp krävs !" msgid "Directory where the rotating log-files are stored" msgstr "Mappen där de roterade logg-filerna lagras" +msgid "During delay ifup-events are not monitored !" +msgstr "" + msgid "Enable HTTPS" msgstr "Aktivera HTTPS" @@ -209,6 +228,9 @@ msgstr "" msgid "OPTIONAL: See python's ssl module for available ciphers" msgstr "VALFRITT: Kolla in python's ssl-modul för tillgängliga chiffer" +msgid "One or more missing/invalid fields on tab" +msgstr "" + msgid "Owner allow write, authenticated users allow read" msgstr "" @@ -289,8 +311,14 @@ msgstr "" "Genom att ställa in den här parametern till '0' så kommer du att stänga av " "rotering av logg-fil." -msgid "Software package '" -msgstr "Mjukvaru-paket '" +msgid "Software package '%s' is not installed." +msgstr "" + +msgid "Software package '%s' is outdated." +msgstr "" + +msgid "Software update required" +msgstr "" msgid "Start" msgstr "Starta" @@ -332,9 +360,15 @@ msgstr "Följ den här länken för att redigera den här filen!" msgid "To view latest log file follow this link!" msgstr "Följ den här länken för att visa den senaste logg-filen" +msgid "Value is not a number" +msgstr "" + msgid "Value is not an Integer >= 0 !" msgstr "Värdet är inte ett heltal >= 0 !" +msgid "Value not between 0 and 300" +msgstr "" + msgid "Value required ! Integer >= 0 !" msgstr "Värde krävs ! Heltal >= 0 !" @@ -375,6 +409,9 @@ msgstr "htpasswd-fil" msgid "installed" msgstr "installerad" +msgid "no valid path given!" +msgstr "" + msgid "or higher" msgstr "eller högre" diff --git a/applications/luci-app-radicale/po/templates/radicale.pot b/applications/luci-app-radicale/po/templates/radicale.pot index c5e079715..1c01c4a17 100644 --- a/applications/luci-app-radicale/po/templates/radicale.pot +++ b/applications/luci-app-radicale/po/templates/radicale.pot @@ -53,6 +53,9 @@ msgstr "" msgid "Auto-start" msgstr "" +msgid "Boot delay" +msgstr "" + msgid "CalDAV/CardDAV" msgstr "" @@ -96,6 +99,9 @@ msgstr "" msgid "Debug" msgstr "" +msgid "Delay (in seconds) during system boot before Radicale start" +msgstr "" + msgid "Directory" msgstr "" @@ -108,6 +114,9 @@ msgstr "" msgid "Directory where the rotating log-files are stored" msgstr "" +msgid "During delay ifup-events are not monitored !" +msgstr "" + msgid "Enable HTTPS" msgstr "" @@ -207,6 +216,9 @@ msgstr "" msgid "OPTIONAL: See python's ssl module for available ciphers" msgstr "" +msgid "One or more missing/invalid fields on tab" +msgstr "" + msgid "Owner allow write, authenticated users allow read" msgstr "" @@ -284,7 +296,13 @@ msgstr "" msgid "Setting this parameter to '0' will disable rotation of log-file." msgstr "" -msgid "Software package '" +msgid "Software package '%s' is not installed." +msgstr "" + +msgid "Software package '%s' is outdated." +msgstr "" + +msgid "Software update required" msgstr "" msgid "Start" @@ -327,9 +345,15 @@ msgstr "" msgid "To view latest log file follow this link!" msgstr "" +msgid "Value is not a number" +msgstr "" + msgid "Value is not an Integer >= 0 !" msgstr "" +msgid "Value not between 0 and 300" +msgstr "" + msgid "Value required ! Integer >= 0 !" msgstr "" @@ -368,6 +392,9 @@ msgstr "" msgid "installed" msgstr "" +msgid "no valid path given!" +msgstr "" + msgid "or higher" msgstr "" -- 2.11.0