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 <christian.schoenebeck@gmail.com>
This commit is contained in:
Christian Schoenebeck 2016-02-07 09:30:29 +01:00
parent 26d009aff9
commit 026ac8d033
9 changed files with 485 additions and 341 deletions

View file

@ -1,5 +1,5 @@
# #
# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org> # Copyright (C) 2008-2016 The LuCI Team <luci@lists.subsignal.org>
# #
# This is free software, licensed under the Apache License, Version 2.0 . # 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 # Version == major.minor.patch
# increase "minor" on new functionality and "patch" on patches/optimization # increase "minor" on new functionality and "patch" on patches/optimization
PKG_VERSION:=1.0.2 PKG_VERSION:=1.1.0
# Release == build # Release == build
# increase on changes of translation files # increase on changes of translation files

View file

@ -1,16 +1,24 @@
-- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com> -- Copyright 2014-2016 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
-- Licensed under the Apache License, Version 2.0 -- Licensed under the Apache License, Version 2.0
module("luci.controller.radicale", package.seeall) module("luci.controller.radicale", package.seeall)
local NX = require("nixio") local NX = require("nixio")
local NXFS = require("nixio.fs") local NXFS = require("nixio.fs")
local DISP = require "luci.dispatcher" local DISP = require("luci.dispatcher")
local HTTP = require("luci.http") local HTTP = require("luci.http")
local I18N = require("luci.i18n") -- not globally avalible here local I18N = require("luci.i18n") -- not globally avalible here
local IPKG = require("luci.model.ipkg")
local UTIL = require("luci.util") local UTIL = require("luci.util")
local SYS = require("luci.sys") 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() function index()
entry( {"admin", "services", "radicale"}, alias("admin", "services", "radicale", "edit"), _("CalDAV/CardDAV"), 58) entry( {"admin", "services", "radicale"}, alias("admin", "services", "radicale", "edit"), _("CalDAV/CardDAV"), 58)
entry( {"admin", "services", "radicale", "edit"}, cbi("radicale") ).leaf = true entry( {"admin", "services", "radicale", "edit"}, cbi("radicale") ).leaf = true
@ -19,6 +27,75 @@ function index()
entry( {"admin", "services", "radicale", "status"}, call("_status") ).leaf = true entry( {"admin", "services", "radicale", "status"}, call("_status") ).leaf = true
end 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.") .. [[<br />]]
.. I18N.translate("Calendars and address books are available for both local and remote access, possibly limited through authentication policies.") .. [[<br />]]
.. I18N.translate("They can be viewed and edited by calendar and contact clients on mobile phones or computers.")
end
function app_title_main()
return [[<a href="javascript:alert(']]
.. I18N.translate("Version Information")
.. [[\n\n]] .. app_name
.. [[\n\t]] .. I18N.translate("Version") .. [[:\t]] .. app_version
.. [[\n\n]] .. srv_name .. [[ ]] .. I18N.translate("required") .. [[:]]
.. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
.. srv_ver_min .. [[ ]] .. I18N.translate("or higher")
.. [[\n\n]] .. srv_name .. [[ ]] .. I18N.translate("installed") .. [[:]]
.. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
.. (service_version() or I18N.translate("NOT installed"))
.. [[\n\n]]
.. [[')">]]
.. I18N.translate(app_title)
.. [[</a>]]
end
function app_title_back()
return [[<a href="]]
.. DISP.build_url("admin", "services", "radicale")
.. [[">]]
.. I18N.translate(app_title)
.. [[</a>]]
end
function app_err_value()
if not service_version() then
return [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
.. I18N.translate("Software package '%s' is not installed." % srv_name)
.. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
.. I18N.translate("required") .. [[: ]] .. srv_name .. [[ ]] .. srv_ver_min
.. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
.. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
.. I18N.translate("Please install current version !")
.. [[</a><br />&nbsp;</strong></h3>]]
else
return [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
.. I18N.translate("Software package '%s' is outdated." % srv_name)
.. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
.. I18N.translate("installed") .. [[: ]] .. srv_name .. [[ ]] .. service_version()
.. [[<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
.. I18N.translate("required") .. [[: ]] .. srv_name .. [[ ]] .. srv_ver_min
.. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
.. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
.. I18N.translate("Please update to current version !")
.. [[</a><br />&nbsp;</strong></h3>]]
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 -- called by XHR.get from detail_logview.htm
function _logread() function _logread()
-- read application settings -- read application settings
@ -60,138 +137,103 @@ function _status()
HTTP.write(tostring(pid)) -- HTTP needs string not number HTTP.write(tostring(pid)) -- HTTP needs string not number
end 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 [[<a href="javascript:alert(']]
.. I18N.translate("Version Information")
.. [[\n\n]] .. luci_app_name()
.. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
.. (ipkg_ver_installed(luci_app_name()) == ""
and I18N.translate("NOT installed")
or ipkg_ver_installed(luci_app_name()) )
.. [[\n\n]] .. service_name() .. [[ ]] .. I18N.translate("required") .. [[:]]
.. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
.. service_required() .. [[ ]] .. I18N.translate("or higher")
.. [[\n\n]] .. service_name() .. [[ ]] .. I18N.translate("installed") .. [[:]]
.. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
.. (service_installed() == "0"
and I18N.translate("NOT installed")
or service_installed())
.. [[\n\n]]
.. [[')">]]
.. I18N.translate("Radicale CalDAV/CardDAV Server")
.. [[</a>]]
end
function app_title_back()
return [[<a href="]]
.. DISP.build_url("admin", "services", "radicale")
.. [[">]]
.. I18N.translate("Radicale CalDAV/CardDAV Server")
.. [[</a>]]
end
function app_description()
return I18N.translate("The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) server solution.") .. [[<br />]]
.. I18N.translate("Calendars and address books are available for both local and remote access, possibly limited through authentication policies.") .. [[<br />]]
.. 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 --return pid of running process
function get_pid() function get_pid()
return tonumber(SYS.exec([[ps | grep "[p]ython.*[r]adicale" 2>/dev/null | awk '{print $1}']])) or 0 return tonumber(SYS.exec([[ps | grep "[p]ython.*[r]adicale" 2>/dev/null | awk '{print $1}']])) or 0
end end
-- compare versions using "<=" "<" ">" ">=" "=" "<<" ">>" -- replacement of build-in parse of "Value"
function ipkg_ver_compare(ver1, comp, ver2) -- modified AbstractValue.parse(self, section, novld) from cbi.lua
if not ver1 or not ver2 -- validate is called if rmempty/optional true or false
or not comp or not (#comp > 0) then return nil end -- before write check if forcewrite, value eq default, and more
-- correct compare string function value_parse(self, section, novld)
if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~=" local fvalue = self:formvalue(section)
elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<=" local fexist = ( fvalue and (#fvalue > 0) ) -- not "nil" and "not empty"
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
end
-- all equal and not compare greater or lower then true
return not (comp == "<" or comp == ">")
end
-- 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()
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) local cvalue = self:cfgvalue(section)
if fvalue ~= self.default or (not self.optional and not self.rmempty) then local rm_opt = ( self.rmempty or self.optional )
self:write(section, fvalue) local eq_cfg -- flag: equal cfgvalue
else
self:remove(section) -- 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
if (fvalue ~= cvalue) then self.section.changed = true end end
else end
self:remove(section) if eq_cfg then
fvalue = cvalue
end
end
-- removed parameter "section" from function call because used/accepted nowhere
-- also removed call to function "transfer"
local vvalue, errtxt = self:validate(fvalue)
-- 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
-- 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
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 self.section.changed = true
end end
end end

View file

@ -1,4 +1,4 @@
-- Copyright 2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com> -- Copyright 2015-2016 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
-- Licensed under the Apache License, Version 2.0 -- Licensed under the Apache License, Version 2.0
local NXFS = require("nixio.fs") local NXFS = require("nixio.fs")
@ -8,7 +8,36 @@ local HTTP = require("luci.http")
local UTIL = require("luci.util") local UTIL = require("luci.util")
local UCI = require("luci.model.uci") local UCI = require("luci.model.uci")
local SYS = require("luci.sys") local SYS = require("luci.sys")
local TOOLS = require("luci.controller.radicale") -- this application's controller and multiused functions 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 = [[<font color="red">]] .. [[<strong>]]
.. translate("Software update required")
.. [[</strong>]] .. [[</font>]]
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 -- ################################################ -- takeover arguments if any -- ################################################
@ -19,8 +48,8 @@ if arg[1] then
-- SimpleForm ------------------------------------------------ -- SimpleForm ------------------------------------------------
local ft = SimpleForm("_text") local ft = SimpleForm("_text")
ft.title = TOOLS.app_title_back() ft.title = CTRL.app_title_back()
ft.description = TOOLS.app_description() ft.description = CTRL.app_description()
ft.redirect = DISP.build_url("admin", "services", "radicale") .. "#cbi-radicale-" .. argument ft.redirect = DISP.build_url("admin", "services", "radicale") .. "#cbi-radicale-" .. argument
if argument == "logger" then if argument == "logger" then
ft.reset = false ft.reset = false
@ -95,54 +124,12 @@ if arg[1] then
end 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 = [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
.. translate("Software package '" .. TOOLS.service_name() .. "' is not installed.")
.. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
.. translate("required") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_required()
.. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
.. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
.. translate("Please install current version !")
.. [[</a><br />&nbsp;</strong></h3>]]
else
v.value = [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
.. translate("Software package '" .. TOOLS.service_name() .. "' is outdated.")
.. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
.. translate("installed") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_installed()
.. [[<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
.. translate("required") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_required()
.. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
.. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
.. translate("Please update to current version !")
.. [[</a><br />&nbsp;</strong></h3>]]
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 -- ################################################################## -- cbi-map -- ##################################################################
local m = Map("radicale") local m = Map("radicale")
m.title = TOOLS.app_title_main() m.title = CTRL.app_title_main()
m.description = TOOLS.app_description() m.description = CTRL.app_description()
m.template = "radicale/tabmap_nsections"
m.tabbed = true
function m.commit_handler(self) function m.commit_handler(self)
if self.changed then -- changes ? if self.changed then -- changes ?
os.execute("/etc/init.d/radicale reload &") -- reload configuration os.execute("/etc/init.d/radicale reload &") -- reload configuration
@ -150,11 +137,14 @@ function m.commit_handler(self)
end end
-- cbi-section "System" -- ##################################################### -- cbi-section "System" -- #####################################################
local sys = m:section( NamedSection, "_system" ) local sys = m:section( NamedSection, "system", "system" )
sys.title = translate("System") sys.title = translate("System")
sys.description = nil sys.description = nil
function sys.cfgvalue(self, section) 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 end
-- start/stop button ----------------------------------------------------------- -- start/stop button -----------------------------------------------------------
@ -165,7 +155,7 @@ btn.rmempty = true
btn.title = translate("Start / Stop") btn.title = translate("Start / Stop")
btn.description = translate("Start/Stop Radicale server") btn.description = translate("Start/Stop Radicale server")
function btn.cfgvalue(self, section) function btn.cfgvalue(self, section)
local pid = TOOLS.get_pid(true) local pid = CTRL.get_pid(true)
if pid > 0 then if pid > 0 then
btn.inputtitle = "PID: " .. pid btn.inputtitle = "PID: " .. pid
btn.inputstyle = "reset" btn.inputstyle = "reset"
@ -183,18 +173,39 @@ local ena = sys:option(Flag, "_enabled")
ena.title = translate("Auto-start") ena.title = translate("Auto-start")
ena.description = translate("Enable/Disable auto-start of Radicale on system start-up and interface events") 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.orientation = "horizontal" -- put description under the checkbox
ena.rmempty = false -- we need write ena.rmempty = false -- force write() function
function ena.cfgvalue(self, section) 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 end
function ena.write(self, section, value) function ena.write(self, section, value)
if value == "1" then if value == self.enabled then
return SYS.init.enable("radicale") return SYS.init.enable("radicale")
else else
return SYS.init.disable("radicale") return SYS.init.disable("radicale")
end end
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")
.. [[<br />]]
.. 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" -- ##################################################### -- cbi-section "Server" -- #####################################################
local srv = m:section( NamedSection, "server", "setting" ) local srv = m:section( NamedSection, "server", "setting" )
srv.title = translate("Server") srv.title = translate("Server")
@ -215,15 +226,17 @@ sh.description = translate("'Hostname:Port' or 'IPv4:Port' or '[IPv6]:Port' Radi
.. [[</strong>]] .. [[</strong>]]
sh.placeholder = "0.0.0.0:5232" sh.placeholder = "0.0.0.0:5232"
sh.rmempty = true sh.rmempty = true
function sh.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
-- realm ----------------------------------------------------------------------- -- realm -----------------------------------------------------------------------
local alm = srv:option( Value, "realm" ) local alm = srv:option( Value, "realm" )
alm.title = translate("Logon message") alm.title = translate("Logon message")
alm.description = translate("Message displayed in the client when a password is needed.") alm.description = translate("Message displayed in the client when a password is needed.")
alm.default = "Radicale - Password Required" alm.default = "Radicale - Password Required"
alm.rmempty = false function alm.parse(self, section, novld)
function alm.parse(self, section) CTRL.value_parse(self, section, novld)
AbstractValue.parse(self, section, "true") -- otherwise unspecific validate error
end end
function alm.validate(self, value) function alm.validate(self, value)
if value then if value then
@ -232,22 +245,11 @@ function alm.validate(self, value)
return self.default return self.default
end end
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 ------------------------------------------------------------------------- -- ssl -------------------------------------------------------------------------
local ssl = srv:option( Flag, "ssl" ) local ssl = srv:option( Flag, "ssl" )
ssl.title = translate("Enable HTTPS") ssl.title = translate("Enable HTTPS")
ssl.description = nil ssl.description = nil
ssl.rmempty = false
function ssl.parse(self, section)
TOOLS.flag_parse(self, section)
end
function ssl.write(self, section, value) function ssl.write(self, section, value)
if value == "0" then -- delete all if not https enabled if value == "0" then -- delete all if not https enabled
self.map:del(section, "protocol") -- protocol 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", "TLS v1")
prt:value ("PROTOCOL_TLSv1_1", "TLS v1.1") prt:value ("PROTOCOL_TLSv1_1", "TLS v1.1")
prt:value ("PROTOCOL_TLSv1_2", "TLS v1.2") prt:value ("PROTOCOL_TLSv1_2", "TLS v1.2")
function prt.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
-- certificate ----------------------------------------------------------------- -- certificate -----------------------------------------------------------------
local crt = srv:option( Value, "certificate" ) local crt = srv:option( Value, "certificate" )
crt.title = translate("Certificate file") crt.title = translate("Certificate file")
crt.description = translate("Full path and file name of certificate") crt.description = translate("Full path and file name of certificate")
crt.placeholder = "/etc/radicale/ssl/server.crt" crt.placeholder = "/etc/radicale/ssl/server.crt"
crt.rmempty = false -- force validate/write
crt:depends ("ssl", "1") crt:depends ("ssl", "1")
function crt.parse(self, section) function crt.parse(self, section, novld)
local _ssl = ssl:formvalue(section) or "0" CTRL.value_parse(self, section, novld)
local novld = (_ssl == "0")
AbstractValue.parse(self, section, novld) -- otherwise unspecific validate error
end end
function crt.validate(self, value) function crt.validate(self, value)
local _ssl = ssl:formvalue(srv.section) or "0" local _ssl = ssl:formvalue(srv.section) or "0"
@ -295,17 +297,10 @@ function crt.validate(self, value)
if DTYP.file(value) then if DTYP.file(value) then
return value return value
else else
return nil, self.title .. " - " .. translate("File not found !") return nil, self.title .. ": " .. translate("File not found !")
end end
else else
return nil, self.title .. " - " .. translate("Path/File required !") 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)
end end
end end
@ -314,12 +309,9 @@ local key = srv:option( Value, "key" )
key.title = translate("Private key file") key.title = translate("Private key file")
key.description = translate("Full path and file name of private key") key.description = translate("Full path and file name of private key")
key.placeholder = "/etc/radicale/ssl/server.key" key.placeholder = "/etc/radicale/ssl/server.key"
key.rmempty = false -- force validate/write
key:depends ("ssl", "1") key:depends ("ssl", "1")
function key.parse(self, section) function key.parse(self, section, novld)
local _ssl = ssl:formvalue(section) or "0" CTRL.value_parse(self, section, novld)
local novld = (_ssl == "0")
AbstractValue.parse(self, section, novld) -- otherwise unspecific validate error
end end
function key.validate(self, value) function key.validate(self, value)
local _ssl = ssl:formvalue(srv.section) or "0" local _ssl = ssl:formvalue(srv.section) or "0"
@ -330,17 +322,10 @@ function key.validate(self, value)
if DTYP.file(value) then if DTYP.file(value) then
return value return value
else else
return nil, self.title .. " - " .. translate("File not found !") return nil, self.title .. ": " .. translate("File not found !")
end end
else else
return nil, self.title .. " - " .. translate("Path/File required !") 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)
end end
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 ("HTTP", "HTTP") -- The HTTP authentication module relies on the requests module
--aty:value ("remote_user", "remote_user") --aty:value ("remote_user", "remote_user")
--aty:value ("custom", translate("custom")) --aty:value ("custom", translate("custom"))
function aty.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function aty.write(self, section, value) function aty.write(self, section, value)
if value ~= "htpasswd" then if value ~= "htpasswd" then
self.map:del(section, "htpasswd_encryption") self.map:del(section, "htpasswd_encryption")
@ -403,9 +391,12 @@ hte:value ("crypt", translate("crypt"))
hte:value ("plain", translate("plain")) hte:value ("plain", translate("plain"))
hte:value ("sha1", translate("SHA-1")) hte:value ("sha1", translate("SHA-1"))
hte:value ("ssha", translate("salted 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) ------------------------------------------------------- -- htpasswd_file (dummy) -------------------------------------------------------
local htf = aut:option( DummyValue, "_htf" ) local htf = aut:option( Value, "_htf" )
htf.title = translate("htpasswd file") htf.title = translate("htpasswd file")
htf.description = [[<strong>]] htf.description = [[<strong>]]
.. translate("Read only!") .. translate("Read only!")
@ -416,9 +407,6 @@ htf.description = [[<strong>]]
.. [[">]] .. [[">]]
.. translate("To edit the file follow this link!") .. translate("To edit the file follow this link!")
.. [[</a>]] .. [[</a>]]
htf.keylist = {} -- required by template
htf.vallist = {} -- required by template
htf.template = "radicale/ro_value"
htf.readonly = true htf.readonly = true
htf:depends ("type", "htpasswd") htf:depends ("type", "htpasswd")
function htf.cfgvalue() 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 ("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 ("from_file", translate("Rights are based on a regexp-based file") )
--rty:value ("custom", "Custom handler") --rty:value ("custom", "Custom handler")
function rty.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function rty.write(self, section, value) function rty.write(self, section, value)
if value ~= "custom" then if value ~= "custom" then
self.map:del(section, "custom_handler") self.map:del(section, "custom_handler")
@ -460,7 +451,7 @@ function rty.write(self, section, value)
end end
-- from_file (dummy) ----------------------------------------------------------- -- from_file (dummy) -----------------------------------------------------------
local rtf = rig:option( DummyValue, "_rtf" ) local rtf = rig:option( Value, "_rtf" )
rtf.title = translate("RegExp file") rtf.title = translate("RegExp file")
rtf.description = [[<strong>]] rtf.description = [[<strong>]]
.. translate("Read only!") .. translate("Read only!")
@ -471,9 +462,6 @@ rtf.description = [[<strong>]]
.. [[">]] .. [[">]]
.. translate("To edit the file follow this link!") .. translate("To edit the file follow this link!")
.. [[</a>]] .. [[</a>]]
rtf.keylist = {} -- required by template
rtf.vallist = {} -- required by template
rtf.template = "radicale/ro_value"
rtf.readonly = true rtf.readonly = true
rtf:depends ("type", "from_file") rtf:depends ("type", "from_file")
function rtf.cfgvalue() function rtf.cfgvalue()
@ -501,6 +489,9 @@ sty:value ("filesystem", translate("File-system"))
--sty:value ("multifilesystem", translate("") ) --sty:value ("multifilesystem", translate("") )
--sty:value ("database", translate("Database") ) --sty:value ("database", translate("Database") )
--sty:value ("custom", translate("Custom") ) --sty:value ("custom", translate("Custom") )
function sty.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function sty.write(self, section, value) function sty.write(self, section, value)
if value ~= "filesystem" then if value ~= "filesystem" then
self.map:del(section, "filesystem_folder") self.map:del(section, "filesystem_folder")
@ -516,13 +507,10 @@ end
local sfi = sto:option( Value, "filesystem_folder" ) local sfi = sto:option( Value, "filesystem_folder" )
sfi.title = translate("Directory") sfi.title = translate("Directory")
sfi.description = nil sfi.description = nil
sfi.default = "/srv/radicale" sfi.placeholder = "/srv/radicale"
sfi.rmempty = false -- force validate/write
sfi:depends ("type", "filesystem") sfi:depends ("type", "filesystem")
function sfi.parse(self, section) function sfi.parse(self, section, novld)
local _typ = sty:formvalue(sto.section) or "" CTRL.value_parse(self, section, novld)
local novld = (_typ ~= "filesystem")
AbstractValue.parse(self, section, novld) -- otherwise unspecific validate error
end end
function sfi.validate(self, value) function sfi.validate(self, value)
local _typ = sty:formvalue(sto.section) or "" local _typ = sty:formvalue(sto.section) or ""
@ -533,10 +521,10 @@ function sfi.validate(self, value)
if DTYP.directory(value) then if DTYP.directory(value) then
return value return value
else else
return nil, self.title .. " - " .. translate("Directory not exists/found !") return nil, self.title .. ": " .. translate("Directory not exists/found !")
end end
else else
return nil, self.title .. " - " .. translate("Directory required !") return nil, self.title .. ": " .. translate("Directory required !")
end end
end end
@ -562,6 +550,9 @@ lco:value ("INFO", translate("Info") )
lco:value ("WARNING", translate("Warning") ) lco:value ("WARNING", translate("Warning") )
lco:value ("ERROR", translate("Error") ) lco:value ("ERROR", translate("Error") )
lco:value ("CRITICAL", translate("Critical") ) lco:value ("CRITICAL", translate("Critical") )
function lco.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function lco.write(self, section, value) function lco.write(self, section, value)
if value ~= self.default then if value ~= self.default then
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
@ -581,6 +572,9 @@ lsl:value ("INFO", translate("Info") )
lsl:value ("WARNING", translate("Warning") ) lsl:value ("WARNING", translate("Warning") )
lsl:value ("ERROR", translate("Error") ) lsl:value ("ERROR", translate("Error") )
lsl:value ("CRITICAL", translate("Critical") ) lsl:value ("CRITICAL", translate("Critical") )
function lsl.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function lsl.write(self, section, value) function lsl.write(self, section, value)
if value ~= self.default then if value ~= self.default then
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
@ -600,6 +594,9 @@ lfi:value ("INFO", translate("Info") )
lfi:value ("WARNING", translate("Warning") ) lfi:value ("WARNING", translate("Warning") )
lfi:value ("ERROR", translate("Error") ) lfi:value ("ERROR", translate("Error") )
lfi:value ("CRITICAL", translate("Critical") ) lfi:value ("CRITICAL", translate("Critical") )
function lfi.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function lfi.write(self, section, value) function lfi.write(self, section, value)
if value ~= self.default then if value ~= self.default then
return self.map:set(section, self.option, value) 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!") .. translate("To view latest log file follow this link!")
.. [[</a>]] .. [[</a>]]
lfp.default = "/var/log/radicale" lfp.default = "/var/log/radicale"
function lfp.write(self, section, value) function lfp.parse(self, section, novld)
if value ~= self.default then CTRL.value_parse(self, section, novld)
return self.map:set(section, self.option, value) end
else function lfp.validate(self, value)
return self.map:del(section, self.option) if not value or (#value < 1) or (value:find("/") ~= 1) then
return nil, self.title .. ": " .. translate("no valid path given!")
end end
return value
end end
-- file_maxbytes --------------------------------------------------------------- -- 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.") .. translate("Setting this parameter to '0' will disable rotation of log-file.")
.. [[</strong>]] .. [[</strong>]]
lmb.default = "8196" lmb.default = "8196"
lmb.rmempty = false function lmb.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function lmb.validate(self, value) function lmb.validate(self, value)
if value then -- otherwise errors in datatype check if value then -- otherwise errors in datatype check
if DTYP.uinteger(value) then if DTYP.uinteger(value) then
return value return value
else else
return nil, self.title .. " - " .. translate("Value is not an Integer >= 0 !") return nil, self.title .. ": " .. translate("Value is not an Integer >= 0 !")
end end
else else
return nil, self.title .. " - " .. translate("Value required ! Integer >= 0 !") 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)
end end
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.") .. translate("Setting this parameter to '0' will disable rotation of log-file.")
.. [[</strong>]] .. [[</strong>]]
lbc.default = "1" lbc.default = "1"
lbc.rmempty = false function lbc.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
function lbc.validate(self, value) function lbc.validate(self, value)
if value then -- otherwise errors in datatype check if value then -- otherwise errors in datatype check
if DTYP.uinteger(value) then if DTYP.uinteger(value) then
return value return value
else else
return nil, self.title .. " - " .. translate("Value is not an Integer >= 0 !") return nil, self.title .. ": " .. translate("Value is not an Integer >= 0 !")
end end
else else
return nil, self.title .. " - " .. translate("Value required ! Integer >= 0 !") 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)
end end
end end
@ -699,14 +688,18 @@ local enr = enc:option( Value, "request" )
enr.title = translate("Response Encoding") enr.title = translate("Response Encoding")
enr.description = translate("Encoding for responding requests.") enr.description = translate("Encoding for responding requests.")
enr.default = "utf-8" enr.default = "utf-8"
enr.optional = true function enr.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
-- stock ----------------------------------------------------------------------- -- stock -----------------------------------------------------------------------
local ens = enc:option( Value, "stock" ) local ens = enc:option( Value, "stock" )
ens.title = translate("Storage Encoding") ens.title = translate("Storage Encoding")
ens.description = translate("Encoding for storing local collections.") ens.description = translate("Encoding for storing local collections.")
ens.default = "utf-8" ens.default = "utf-8"
ens.optional = true function ens.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
-- cbi-section "Headers" -- #################################################### -- cbi-section "Headers" -- ####################################################
local hea = m:section( NamedSection, "headers", "setting" ) local hea = m:section( NamedSection, "headers", "setting" )
@ -724,25 +717,32 @@ end
local heo = hea:option( DynamicList, "Access_Control_Allow_Origin" ) local heo = hea:option( DynamicList, "Access_Control_Allow_Origin" )
heo.title = translate("Access-Control-Allow-Origin") heo.title = translate("Access-Control-Allow-Origin")
heo.description = nil heo.description = nil
heo.default = "*" function heo.parse(self, section, novld)
heo.optional = true CTRL.value_parse(self, section, novld)
end
-- Access_Control_Allow_Methods ------------------------------------------------ -- Access_Control_Allow_Methods ------------------------------------------------
local hem = hea:option( DynamicList, "Access_Control_Allow_Methods" ) local hem = hea:option( DynamicList, "Access_Control_Allow_Methods" )
hem.title = translate("Access-Control-Allow-Methods") hem.title = translate("Access-Control-Allow-Methods")
hem.description = nil hem.description = nil
hem.optional = true function hem.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
-- Access_Control_Allow_Headers ------------------------------------------------ -- Access_Control_Allow_Headers ------------------------------------------------
local heh = hea:option( DynamicList, "Access_Control_Allow_Headers" ) local heh = hea:option( DynamicList, "Access_Control_Allow_Headers" )
heh.title = translate("Access-Control-Allow-Headers") heh.title = translate("Access-Control-Allow-Headers")
heh.description = nil heh.description = nil
heh.optional = true function heh.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
-- Access_Control_Expose_Headers ----------------------------------------------- -- Access_Control_Expose_Headers -----------------------------------------------
local hee = hea:option( DynamicList, "Access_Control_Expose_Headers" ) local hee = hea:option( DynamicList, "Access_Control_Expose_Headers" )
hee.title = translate("Access-Control-Expose-Headers") hee.title = translate("Access-Control-Expose-Headers")
hee.description = nil hee.description = nil
hee.optional = true function hee.parse(self, section, novld)
CTRL.value_parse(self, section, novld)
end
return m return m

View file

@ -4,7 +4,7 @@
// show XHR.poll/XHR.get response on button // show XHR.poll/XHR.get response on button
function _data2elements(x) { 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 ( ! btn ) { return; } // security check
if (x.responseText == "0") { if (x.responseText == "0") {
btn.value = "<%:Start%>"; btn.value = "<%:Start%>";
@ -21,12 +21,12 @@
function onclick_startstop(id) { function onclick_startstop(id) {
// do start/stop // do start/stop
var btnXHR = new XHR(); 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); } 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); } function(x, data) { _data2elements(x); }
); );

View file

@ -1,35 +0,0 @@
<%+cbi/valueheader%>
<input type="<%=self.password and 'password" class="cbi-input-password' or 'text" class="cbi-input-text' %>" onchange="cbi_d_update(this.id)"<%=
attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) ..
ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder") .. ifattr(self.readonly, "readonly")
%> />
<% if self.password then %><img src="<%=resource%>/cbi/reload.gif" style="vertical-align:middle" title="<%:Reveal/hide password%>" onclick="var e = document.getElementById('<%=cbid%>'); e.type = (e.type=='password') ? 'text' : 'password';" /><% end %>
<% if #self.keylist > 0 or self.datatype then -%>
<script type="text/javascript">//<![CDATA[
<% if #self.keylist > 0 then -%>
cbi_combobox_init('<%=cbid%>', {
<%-
for i, k in ipairs(self.keylist) do
-%>
<%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%>
<%-if i<#self.keylist then-%>,<%-end-%>
<%-
end
-%>
}, '<%- if not self.rmempty and not self.optional then -%>
<%-: -- Please choose -- -%>
<%- elseif self.placeholder then -%>
<%-= pcdata(self.placeholder) -%>
<%- end -%>', '
<%- if self.combobox_manual then -%>
<%-=self.combobox_manual-%>
<%- else -%>
<%-: -- custom -- -%>
<%- end -%>');
<%- end %>
<% if self.datatype then -%>
cbi_validate_field('<%=cbid%>', <%=tostring((self.optional or self.rmempty) == true)%>, '<%=self.datatype:gsub("'", "\\'")%>');
<%- end %>
//]]></script>
<% end -%>
<%+cbi/valuefooter%>

View file

@ -0,0 +1,49 @@
<%- if firstmap and messages then local msg; for _, msg in ipairs(messages) do -%>
<div class="errorbox"><%=pcdata(msg)%></div>
<%- end end -%>
<%-+cbi/apply_xhr-%>
<div class="cbi-map" id="cbi-<%=self.config%>">
<% if self.title and #self.title > 0 then %><h2 name="content"><%=self.title%></h2><% end %>
<% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
<%- if firstmap and applymap then cbi_apply_xhr(self.config, parsechain, redirect) end -%>
<% if self.tabbed then %>
<ul class="cbi-tabmenu map">
<%- 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 %>
<li id="tab.m-<%=self.config%>.<%=section.section or section.sectiontype%>" class="cbi-tab<%=(section.sectiontype == self.selected_tab) and '' or '-disabled'%>">
<a onclick="this.blur(); return cbi_t_switch('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')" href="<%=REQUEST_URI%>?tab.m-<%=self.config%>=<%=section.section or section.sectiontype%>"><%=section.title or section.section or section.sectiontype %></a>
<% if section.sectiontype == self.selected_tab then %><input type="hidden" id="tab.m-<%=self.config%>" name="tab.m-<%=self.config%>" value="<%=section.section or section.sectiontype%>" /><% end %>
</li>
<% end %>
</ul>
<br />
<% for i, section in ipairs(self.children) do %>
<div class="cbi-tabcontainer" id="container.m-<%=self.config%>.<%=section.section or section.sectiontype%>"<% if section.sectiontype ~= self.selected_tab then %> style="display:none"<% end %>>
<% section:render() %>
</div>
<script type="text/javascript">cbi_t_add('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')</script>
<% end %>
<% else %>
<%- self:render_children() %>
<% end %>
<% if not self.save then -%>
<div class="cbi-section-error">
<% for _, section in ipairs(self.children) do %>
<% if section.error and section.error[section.section] then -%>
<ul><li>
<%:One or more missing/invalid fields on tab%>:&nbsp;<%=section.title or section.section or section.sectiontype%>
</li></ul>
<%- end %>
<% end %>
</div>
<%- end %>
<br />
</div>

View file

@ -1,15 +1,15 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: luci-app-radicale\n" "Project-Id-Version: luci-app-radicale 1.1.0-1\n"
"POT-Creation-Date: 2015-05-02 19:32+0100\n" "POT-Creation-Date: 2016-01-30 20:34+0100\n"
"PO-Revision-Date: 2015-05-02 22:43+0100\n" "PO-Revision-Date: 2016-01-31 20:49+0100\n"
"Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n" "Last-Translator: Christian Schönebeck <christian.schoenebeck@gmail.com>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: de\n" "Language: de\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-SourceCharset: UTF-8\n"
@ -72,6 +72,9 @@ msgstr ""
msgid "Auto-start" msgid "Auto-start"
msgstr "Autostart" msgstr "Autostart"
msgid "Boot delay"
msgstr "Systemstart-Verzögerung"
msgid "CalDAV/CardDAV" msgid "CalDAV/CardDAV"
msgstr "CalDAV/CardDAV" msgstr "CalDAV/CardDAV"
@ -122,6 +125,10 @@ msgstr "Datenbank"
msgid "Debug" msgid "Debug"
msgstr "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" msgid "Directory"
msgstr "Verzeichnis" msgstr "Verzeichnis"
@ -135,6 +142,9 @@ msgid "Directory where the rotating log-files are stored"
msgstr "" msgstr ""
"Verzeichnis in dem die rollierenden Protokolldateien gespeichert werden" "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" msgid "Enable HTTPS"
msgstr "Verwende 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" msgid "OPTIONAL: See python's ssl module for available ciphers"
msgstr "OPTIONAL: Siehe Python SSL-Modul Dokumentation" 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" msgid "Owner allow write, authenticated users allow read"
msgstr "" msgstr ""
"Besitzer haben Schreibrechte, Authentifizierten Benutzer dürfen nur lesen." "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 " "Wenn dieser Parameter auf '0' gesetzt wird, wird die Protokolldatei nicht "
"mehr rolliert!" "mehr rolliert!"
msgid "Software package '" msgid "Software package '%s' is not installed."
msgstr "Software Packet '" 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" msgid "Start"
msgstr "Start" msgstr "Start"
@ -372,9 +391,15 @@ msgid "To view latest log file follow this link!"
msgstr "" msgstr ""
"Zur Anzeige der letzten Protokolldatei, folgen Sie dieser Verknüpfung !" "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 !" msgid "Value is not an Integer >= 0 !"
msgstr "Eingabe ist keine Ganzzahl >= 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 !" msgid "Value required ! Integer >= 0 !"
msgstr "Eingabe erforderlich ! Ganzzahl >= 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}, " "You can also get groups from the user regex in the collection with {0}, {1}, "
"etc." "etc."
msgstr "" msgstr ""
"Sie können auch Gruppen aus der Benutzer regex in der Sammlung mit {0}, {1} "
"usw. bekommen."
msgid "" msgid ""
"You can use Python's ConfigParser interpolation values %(login)s and " "You can use Python's ConfigParser interpolation values %(login)s and "
@ -416,6 +443,9 @@ msgstr "htpasswd Datei"
msgid "installed" msgid "installed"
msgstr "installiert" msgstr "installiert"
msgid "no valid path given!"
msgstr "Keine gültige Pfadangabe!"
msgid "or higher" msgid "or higher"
msgstr "oder höher" msgstr "oder höher"
@ -427,9 +457,3 @@ msgstr "erforderlich"
msgid "salted SHA-1" msgid "salted SHA-1"
msgstr "Salted SHA-1" msgstr "Salted SHA-1"
#~ msgid "File"
#~ msgstr "Datei"
#~ msgid "not found !"
#~ msgstr "nicht gefunden !"

View file

@ -1,5 +1,15 @@
msgid "" 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 "" msgid ""
"'AUTO' selects the highest protocol version that client and server support." "'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" msgid "Auto-start"
msgstr "Starta automatiskt" msgstr "Starta automatiskt"
msgid "Boot delay"
msgstr ""
msgid "CalDAV/CardDAV" msgid "CalDAV/CardDAV"
msgstr "CalDAV/CardDAV" msgstr "CalDAV/CardDAV"
@ -98,6 +111,9 @@ msgstr "Databas"
msgid "Debug" msgid "Debug"
msgstr "Felsök" msgstr "Felsök"
msgid "Delay (in seconds) during system boot before Radicale start"
msgstr ""
msgid "Directory" msgid "Directory"
msgstr "Mapp" msgstr "Mapp"
@ -110,6 +126,9 @@ msgstr "Mapp krävs !"
msgid "Directory where the rotating log-files are stored" msgid "Directory where the rotating log-files are stored"
msgstr "Mappen där de roterade logg-filerna lagras" msgstr "Mappen där de roterade logg-filerna lagras"
msgid "During delay ifup-events are not monitored !"
msgstr ""
msgid "Enable HTTPS" msgid "Enable HTTPS"
msgstr "Aktivera HTTPS" msgstr "Aktivera HTTPS"
@ -209,6 +228,9 @@ msgstr ""
msgid "OPTIONAL: See python's ssl module for available ciphers" msgid "OPTIONAL: See python's ssl module for available ciphers"
msgstr "VALFRITT: Kolla in python's ssl-modul för tillgängliga chiffer" 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" msgid "Owner allow write, authenticated users allow read"
msgstr "" msgstr ""
@ -289,8 +311,14 @@ msgstr ""
"Genom att ställa in den här parametern till '0' så kommer du att stänga av " "Genom att ställa in den här parametern till '0' så kommer du att stänga av "
"rotering av logg-fil." "rotering av logg-fil."
msgid "Software package '" msgid "Software package '%s' is not installed."
msgstr "Mjukvaru-paket '" msgstr ""
msgid "Software package '%s' is outdated."
msgstr ""
msgid "Software update required"
msgstr ""
msgid "Start" msgid "Start"
msgstr "Starta" 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!" 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" 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 !" msgid "Value is not an Integer >= 0 !"
msgstr "Värdet är inte ett heltal >= 0 !" msgstr "Värdet är inte ett heltal >= 0 !"
msgid "Value not between 0 and 300"
msgstr ""
msgid "Value required ! Integer >= 0 !" msgid "Value required ! Integer >= 0 !"
msgstr "Värde krävs ! Heltal >= 0 !" msgstr "Värde krävs ! Heltal >= 0 !"
@ -375,6 +409,9 @@ msgstr "htpasswd-fil"
msgid "installed" msgid "installed"
msgstr "installerad" msgstr "installerad"
msgid "no valid path given!"
msgstr ""
msgid "or higher" msgid "or higher"
msgstr "eller högre" msgstr "eller högre"

View file

@ -53,6 +53,9 @@ msgstr ""
msgid "Auto-start" msgid "Auto-start"
msgstr "" msgstr ""
msgid "Boot delay"
msgstr ""
msgid "CalDAV/CardDAV" msgid "CalDAV/CardDAV"
msgstr "" msgstr ""
@ -96,6 +99,9 @@ msgstr ""
msgid "Debug" msgid "Debug"
msgstr "" msgstr ""
msgid "Delay (in seconds) during system boot before Radicale start"
msgstr ""
msgid "Directory" msgid "Directory"
msgstr "" msgstr ""
@ -108,6 +114,9 @@ msgstr ""
msgid "Directory where the rotating log-files are stored" msgid "Directory where the rotating log-files are stored"
msgstr "" msgstr ""
msgid "During delay ifup-events are not monitored !"
msgstr ""
msgid "Enable HTTPS" msgid "Enable HTTPS"
msgstr "" msgstr ""
@ -207,6 +216,9 @@ msgstr ""
msgid "OPTIONAL: See python's ssl module for available ciphers" msgid "OPTIONAL: See python's ssl module for available ciphers"
msgstr "" msgstr ""
msgid "One or more missing/invalid fields on tab"
msgstr ""
msgid "Owner allow write, authenticated users allow read" msgid "Owner allow write, authenticated users allow read"
msgstr "" msgstr ""
@ -284,7 +296,13 @@ msgstr ""
msgid "Setting this parameter to '0' will disable rotation of log-file." msgid "Setting this parameter to '0' will disable rotation of log-file."
msgstr "" msgstr ""
msgid "Software package '" msgid "Software package '%s' is not installed."
msgstr ""
msgid "Software package '%s' is outdated."
msgstr ""
msgid "Software update required"
msgstr "" msgstr ""
msgid "Start" msgid "Start"
@ -327,9 +345,15 @@ msgstr ""
msgid "To view latest log file follow this link!" msgid "To view latest log file follow this link!"
msgstr "" msgstr ""
msgid "Value is not a number"
msgstr ""
msgid "Value is not an Integer >= 0 !" msgid "Value is not an Integer >= 0 !"
msgstr "" msgstr ""
msgid "Value not between 0 and 300"
msgstr ""
msgid "Value required ! Integer >= 0 !" msgid "Value required ! Integer >= 0 !"
msgstr "" msgstr ""
@ -368,6 +392,9 @@ msgstr ""
msgid "installed" msgid "installed"
msgstr "" msgstr ""
msgid "no valid path given!"
msgstr ""
msgid "or higher" msgid "or higher"
msgstr "" msgstr ""