From d9902c0664fc6b98862e0d0b03c6cca317f0d74e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 30 Jan 2013 21:20:58 +0100 Subject: [PATCH] Adjustments for the Gluon project --- package/gluon-config-mode/Makefile | 38 +++++++++++ .../files/etc/config/config_mode | 3 + .../files/etc/hotplug.d/button/50-config-mode | 29 ++++++++ .../files/etc/init.d/config_mode | 53 +++++++++++++++ .../lua/luci/controller/freifunk/index.lua | 13 ++++ .../lua/luci/controller/freifunk/wizard.lua | 30 ++++++++ .../model/cbi/freifunk-wizard/hostname.lua | 38 +++++++++++ .../model/cbi/freifunk-wizard/meshvpn.lua | 67 ++++++++++++++++++ .../model/cbi/freifunk-wizard/password.lua | 43 ++++++++++++ .../lua/luci/tools/freifunk-wizard/nav.lua | 43 ++++++++++++ .../luci/view/freifunk-wizard/completed.htm | 16 +++++ .../lua/luci/view/freifunk-wizard/footer.htm | 19 ++++++ .../lua/luci/view/freifunk-wizard/header.htm | 24 +++++++ .../luci/view/freifunk-wizard/meshvpn-key.htm | 18 +++++ .../lib/lua/luci/view/freifunk-wizard/nav.htm | 15 ++++ .../lua/luci/view/freifunk-wizard/welcome.htm | 19 ++++++ .../luci/view/freifunk-wizard/wizardform.htm | 68 +++++++++++++++++++ 17 files changed, 536 insertions(+) create mode 100644 package/gluon-config-mode/Makefile create mode 100644 package/gluon-config-mode/files/etc/config/config_mode create mode 100755 package/gluon-config-mode/files/etc/hotplug.d/button/50-config-mode create mode 100755 package/gluon-config-mode/files/etc/init.d/config_mode create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/index.lua create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/wizard.lua create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/hostname.lua create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/meshvpn.lua create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/password.lua create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/tools/freifunk-wizard/nav.lua create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/completed.htm create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/footer.htm create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/header.htm create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/meshvpn-key.htm create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/nav.htm create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/welcome.htm create mode 100644 package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/wizardform.htm diff --git a/package/gluon-config-mode/Makefile b/package/gluon-config-mode/Makefile new file mode 100644 index 00000000..2cdac318 --- /dev/null +++ b/package/gluon-config-mode/Makefile @@ -0,0 +1,38 @@ +# Copyright (C) 2012 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-config-mode +PKG_RELEASE:=0.0.1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-config-mode + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci based config mode for user friendly setup of new meshnodes + DEPENDS:=+luci-mod-admin-core +endef + +define Package/gluon-config-mode/description + Luci based config mode +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-config-mode/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-config-mode)) diff --git a/package/gluon-config-mode/files/etc/config/config_mode b/package/gluon-config-mode/files/etc/config/config_mode new file mode 100644 index 00000000..179b22bf --- /dev/null +++ b/package/gluon-config-mode/files/etc/config/config_mode @@ -0,0 +1,3 @@ +config wizard + option enabled '1' + option configured '0' diff --git a/package/gluon-config-mode/files/etc/hotplug.d/button/50-config-mode b/package/gluon-config-mode/files/etc/hotplug.d/button/50-config-mode new file mode 100755 index 00000000..0e4e8a89 --- /dev/null +++ b/package/gluon-config-mode/files/etc/hotplug.d/button/50-config-mode @@ -0,0 +1,29 @@ +#!/bin/sh + + +wait=3 + + +wait_config_mode() { + sleep $wait + uci set 'config_mode.@wizard[0].enabled=1' + uci commit config_mode + reboot +} + + +if [ "$BUTTON" = wps -o "$BUTTON" = reset ]; then + case "$ACTION" in + pressed) + wait_config_mode & + PID=$! + echo $PID > /tmp/.wait_config_mode + ;; + released) + if [ -r /tmp/.wait_config_mode ]; then + kill $(cat /tmp/.wait_config_mode) + rm /tmp/.wait_config_mode + fi + ;; + esac +fi diff --git a/package/gluon-config-mode/files/etc/init.d/config_mode b/package/gluon-config-mode/files/etc/init.d/config_mode new file mode 100755 index 00000000..e4b5efb2 --- /dev/null +++ b/package/gluon-config-mode/files/etc/init.d/config_mode @@ -0,0 +1,53 @@ +#!/bin/sh /etc/rc.common + +START=12 + + +config_mode_iface=eth0 +config_mode_addr=192.168.1.1 +config_mode_plen=24 + +config_mode_dnsname=freifunk +config_mode_dhcp_range=192.168.1.2,192.168.1.254 + +check_enable() { + config_get enabled "$1" enabled + config_get configured "$1" configured + + if [ "$enabled" = 1 -o "$configured" != 1 ]; then + export enable=1 + fi +} + +start() { + enable=0 + config_load config_mode + config_foreach check_enable wizard + + if [ "$enable" = '1' ]; then + lua -luci -e 'require "luci.model.uci"; uci_state=luci.model.uci.cursor_state(); uci_state:section("config_mode", "wizard", nil, { running = "1" }); uci_state:save("config_mode")' + uci set 'config_mode.@wizard[0].enabled=0' + uci commit config_mode + + ip addr add $config_mode_addr/$config_mode_plen dev $config_mode_iface + ip link set up dev $config_mode_iface + + /etc/init.d/telnet start + /etc/init.d/dropbear start + /etc/init.d/uhttpd start + /etc/init.d/led start + + # correctly finish firstboot + /etc/init.d/done boot + + echo "$config_mode_addr $config_mode_dnsname" > /tmp/hosts.config_mode + dnsmasq -h -H /tmp/hosts.config_mode -R -F interface:$config_mode_iface,$config_mode_dhcp_range -l /tmp/dhcp.leases -O option:router + + . /etc/diag.sh + get_status_led + status_led_set_timer 1000 300 + + # block further boot + while true; do sleep 1; done + fi +} diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/index.lua b/package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/index.lua new file mode 100644 index 00000000..cc2bcadb --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/index.lua @@ -0,0 +1,13 @@ +module("luci.controller.freifunk.index", package.seeall) + + +function index() + local uci_state = luci.model.uci.cursor_state() + + if uci_state:get_first("config_mode", "wizard", "running", "0") == "1" then + local root = node() + root.target = alias("wizard", "welcome") + root.index = true + end +end + diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/wizard.lua b/package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/wizard.lua new file mode 100644 index 00000000..ab64f4f8 --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/controller/freifunk/wizard.lua @@ -0,0 +1,30 @@ +module("luci.controller.freifunk.wizard", package.seeall) + +function index() + local uci_state = luci.model.uci.cursor_state() + if uci_state:get_first("config_mode", "wizard", "running", "0") == "1" then + entry({"wizard", "welcome"}, template("freifunk-wizard/welcome"), "Willkommen", 10).dependent=false + entry({"wizard", "password"}, form("freifunk-wizard/password"), "Passwort", 20).dependent=false + entry({"wizard", "hostname"}, form("freifunk-wizard/hostname"), "Hostname", 30).dependent=false + entry({"wizard", "meshvpn"}, form("freifunk-wizard/meshvpn"), "Mesh-VPN", 40).dependent=false + entry({"wizard", "meshvpn", "pubkey"}, template("freifunk-wizard/meshvpn-key"), "Mesh-VPN Key", 1).dependent=false + entry({"wizard", "completed"}, template("freifunk-wizard/completed"), "Fertig", 50).dependent=false + entry({"wizard", "completed", "reboot"}, call("reboot"), "reboot", 1).dependent=false + end +end + +function reboot() + local uci = luci.model.uci.cursor() + + uci:foreach("config_mode", "wizard", + function(s) + uci:set("config_mode", s[".name"], "configured", "1") + end + ) + + uci:save("config_mode") + uci:commit("config_mode") + + luci.sys.reboot() +end + diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/hostname.lua b/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/hostname.lua new file mode 100644 index 00000000..ed387f9f --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/hostname.lua @@ -0,0 +1,38 @@ +local uci = luci.model.uci.cursor() + +local nav = require "luci.tools.freifunk-wizard.nav" + +local f = SimpleForm("hostname", "Name deines Freifunkknotens", "Als nächstes solltest du einem Freifunkknoten einen individuellen Namen geben. Dieser hilft dir und auch uns den Überblick zu behalten.") +f.template = "freifunk-wizard/wizardform" + +hostname = f:field(Value, "hostname", "Hostname") +hostname.value = uci:get_first("system", "system", "hostname") +hostname.rmempty = false + +function hostname.validate(self, value, section) + return value +end + +function f.handle(self, state, data) + if state == FORM_VALID then + local stat = true + uci:foreach("system", "system", function(s) + stat = stat and uci:set("system", s[".name"], "hostname", data.hostname) + end + ) + + stat = stat and uci:save("system") + stat = stat and uci:commit("system") + + if stat then + nav.maybe_redirect_to_successor() + f.message = "Hostname geändert!" + else + f.errmessage = "Fehler!" + end + end + + return true +end + +return f diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/meshvpn.lua b/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/meshvpn.lua new file mode 100644 index 00000000..6ca35c8a --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/meshvpn.lua @@ -0,0 +1,67 @@ +local meshvpn_name = "mesh_vpn" + +local uci = luci.model.uci.cursor() +local nav = require "luci.tools.freifunk-wizard.nav" + +local f = SimpleForm("meshvpn", "Mesh-VPN", "

Um deinen Freifunkknoten auch über das Internet mit dem Freifunk-Netzwerk zu verbinden, kann das Mesh-VPN aktiviert werden.\ +Dies erlaubt es, den Freifunk-Knoten zu betreiben, auch wenn es keine anderen Knoten in deiner Umgebung gibt, mit denen eine WLAN-Verbindung möglich ist.

\ +

Dabei wird zur Kommunikation ein verschlüsselter Tunnel verwendet, sodass für den Anschluss-Inhaber keinerlei Risiken entstehen.

\ +

Damit das Mesh-VPN deine Internet-Verbindung nicht unverhältnismäßig auslastet, kann die Bandbreite begrenzt werden. Wenn du zum Beispiel eine DSL-16000-Leitung hast\ +und maximal ein Viertel der Leitung zur Verfügung stellen willst, muss als Downstream-Bandbreite 4000 kbit/s eingetragen werden.

\ +

Um das Freifunk-Netz nicht zu sehr auszubremsen, bitten wir darum, mindestens 1000 kbit/s im Downstream und 100 kbit/s im Upstream bereitzustellen.

") +f.template = "freifunk-wizard/wizardform" + +meshvpn = f:field(Flag, "meshvpn", "Mesh-VPN aktivieren?") +meshvpn.default = string.format("%d", uci:get("fastd", meshvpn_name, "enabled", "0")) +meshvpn.rmempty = false + +tc = f:field(Flag, "tc", "Bandbreitenbegrenzung aktivieren?") +tc.default = string.format("%d", uci:get_first("freifunk", "bandwidth", "enabled", "0")) +tc.rmempty = false + +downstream = f:field(Value, "downstream", "Downstream-Bandbreite (kbit/s)") +downstream.value = uci:get_first("freifunk", "bandwidth", "downstream", "0") +upstream = f:field(Value, "upstream", "Upstream-Bandbreite (kbit/s)") +upstream.value = uci:get_first("freifunk", "bandwidth", "upstream", "0") + +function f.handle(self, state, data) + if state == FORM_VALID then + local stat = false + uci:set("fastd", meshvpn_name, "enabled", data.meshvpn) + uci:save("fastd") + uci:commit("fastd") + + uci:foreach("freifunk", "bandwidth", function(s) + uci:set("freifunk", s[".name"], "upstream", data.upstream) + uci:set("freifunk", s[".name"], "downstream", data.downstream) + uci:set("freifunk", s[".name"], "enabled", data.tc) + end + ) + + uci:save("freifunk") + uci:commit("freifunk") + + if data.meshvpn == "1" then + local secret = uci:get("fastd", meshvpn_name, "secret") + if not secret or not secret:match("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x") then + luci.sys.call("/etc/init.d/haveged start") + local f = io.popen("fastd --generate-key --machine-readable", "r") + local secret = f:read("*a") + f:close() + luci.sys.call("/etc/init.d/haveged stop") + + uci:set("fastd", meshvpn_name, "secret", secret) + uci:save("fastd") + uci:commit("fastd") + + end + luci.http.redirect(luci.dispatcher.build_url("wizard", "meshvpn", "pubkey")) + else + nav.maybe_redirect_to_successor() + end + end + + return true +end + +return f diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/password.lua b/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/password.lua new file mode 100644 index 00000000..b752b848 --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/model/cbi/freifunk-wizard/password.lua @@ -0,0 +1,43 @@ +local nav = require "luci.tools.freifunk-wizard.nav" + +f = SimpleForm("password", "Administrator-Passwort setzen", "

Damit nur du Zugriff auf deinen Freifunkknoten hast, solltest du jetzt ein Passwort vergeben. \ +Da man mit Hilfe von diesem beliebige Einstellungen geändert werden können, sollte es möglichst sicher sein.

\ +

Bitte beachte dazu folgende Hinweise:

\ +") +f.template = "freifunk-wizard/wizardform" + +pw1 = f:field(Value, "pw1", "Passwort") +pw1.password = true +pw1.rmempty = false + +pw2 = f:field(Value, "pw2", "Wiederholung") +pw2.password = true +pw2.rmempty = false + +function pw2.validate(self, value, section) + return pw1:formvalue(section) == value and value +end + +function f.handle(self, state, data) + if state == FORM_VALID then + local stat = luci.sys.user.setpasswd("root", data.pw1) == 0 + + if stat then + nav.maybe_redirect_to_successor() + f.message = "Passwort geändert!" + else + f.errmessage = "Fehler!" + end + + data.pw1 = nil + data.pw2 = nil + end + + return true +end + +return f diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/tools/freifunk-wizard/nav.lua b/package/gluon-config-mode/files/usr/lib/lua/luci/tools/freifunk-wizard/nav.lua new file mode 100644 index 00000000..ec6c0a12 --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/tools/freifunk-wizard/nav.lua @@ -0,0 +1,43 @@ +module("luci.tools.freifunk-wizard.nav", package.seeall) + +function maybe_redirect_to_successor() + local pre, suc = get() + + if suc then + luci.http.redirect(luci.dispatcher.build_url("wizard", suc.href)) + end +end + +function get() + + local disp = require "luci.dispatcher" + + local request = disp.context.path + local category = request[1] + local cattree = category and disp.node(category) + + local childs = disp.node_childs(cattree) + + local predecessor = nil + local successor = nil + + if #childs > 0 then + local found_pre = false + for i, r in ipairs(childs) do + local nnode = cattree.nodes[r] + nnode.href = r + + if r == request[2] then + found_pre = true + elseif found_pre and successor == nil then + successor = nnode + end + + if not found_pre then + predecessor = nnode + end + end + end + + return predecessor, successor +end diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/completed.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/completed.htm new file mode 100644 index 00000000..3c096b7d --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/completed.htm @@ -0,0 +1,16 @@ +<% + local disp = require "luci.dispatcher" +%> +<%+header%> +

Konfiguration abgeschlossen

+ +

Die Konfiguration deines Freifunkknotens ist nun abgeschlossen. Damit sie aktiv wird, muss der Knoten neugestartet werden.

+ +

Um später wieder in den Konfiguration-Modus zurückzukehren, zum Beispiel um die Konfiguration zu verändern oder ein Firmware-Upgrade durchzuführen, + muss der QSS-Button am Gehäuse für einige Sekunden gedrückt gehalten werden, während der Knoten läuft. Der Knoten wird dann neu starten und in + den Konfigurationsmodus zurückkehren.

+ +

+ ">Jetzt neustarten! +

+<%+footer%> diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/footer.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/footer.htm new file mode 100644 index 00000000..57e20f31 --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/footer.htm @@ -0,0 +1,19 @@ +<% local xtime +if exectime then + xtime = (string.format("%.2fs", os.clock() - exectime)) +end %> + + + + + + + + diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/header.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/header.htm new file mode 100644 index 00000000..7c28bc43 --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/header.htm @@ -0,0 +1,24 @@ +<% + local fs = require "luci.fs" + local sys = require "luci.sys" + local http = require "luci.http" + local disp = require "luci.dispatcher" + + local hostname = sys.hostname() +%> + + + + + + +<%=striptags( hostname )%> - Wizard + + + + +
+ + diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/meshvpn-key.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/meshvpn-key.htm new file mode 100644 index 00000000..781dd11b --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/meshvpn-key.htm @@ -0,0 +1,18 @@ +<% + local meshvpn_name = "mesh_vpn" + local address = "freifunk.luebeck@asta.uni-luebeck.de" + + local disp = require "luci.dispatcher" + local f = io.popen("/etc/init.d/fastd show_key " .. meshvpn_name, "r") + local key = f:read("*a") + f:close() + +%> +<%+header%> +

Schlüsselaustausch

+

Dies ist der öffentliche Schlüssel deines Freifunkknotens. Bitte schicke ihn an <%=address%>, um ihn auf den Freifunkservern eintragen zu lassen. Sobald der Schlüssel eingetragen wurde, kann dein Knoten das Mesh-VPN nutzen.

+
+ <%=key%> +
+<%+freifunk-wizard/nav%> +<%+footer%> diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/nav.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/nav.htm new file mode 100644 index 00000000..ca46eaee --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/nav.htm @@ -0,0 +1,15 @@ +<% + local nav = require "luci.tools.freifunk-wizard.nav" + local predecessor, successor = nav.get() +%> + +
+ +<% if successor then %> + ">Weiter +<% end %> + +<% if predecessor then %> + ">Zurück +<% end %> +
diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/welcome.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/welcome.htm new file mode 100644 index 00000000..259f4d85 --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/welcome.htm @@ -0,0 +1,19 @@ +<% + local disp = require "luci.dispatcher" + local nav = require "luci.tools.freifunk-wizard.nav" + local predecessor, successor = nav.get() +%> +<%+header%> +

Willkommen auf deinem Freifunkknoten!

+

Danke, dass du Freifunk unterstützt.

+

Dieser Wizard hilft dir nun deinen Knoten einzurichten. Dabei führt er dich schrittweise durch die wichtigsten Punkte.

+ +
+<% if successor then %> + ">Knoten neu einrichten +<% end %> + + ">Firmwareupgrade einspielen +
+<%+footer%> + diff --git a/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/wizardform.htm b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/wizardform.htm new file mode 100644 index 00000000..875f448b --- /dev/null +++ b/package/gluon-config-mode/files/usr/lib/lua/luci/view/freifunk-wizard/wizardform.htm @@ -0,0 +1,68 @@ +<% if not self.embedded then %> +
+
+ + +
+<% end %> +
+ <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> + <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> + <% self:render_children() %> +
+
+<%- if self.message then %> +
<%=self.message%>
+<%- end %> +<%- if self.errmessage then %> +
<%=self.errmessage%>
+<%- end %> +<% if not self.embedded then %> +
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> +
+<% if redirect then %> +
+ +
+<% end %> +<%- if self.flow and self.flow.skip then %> + +<% end %> +<%- if self.submit ~= false then %> + +<% end %> +<%- if self.reset ~= false then %> + +<% end %> +<%- if self.cancel ~= false and self.on_cancel then %> + +<% end %> +<% + local nav = require "luci.tools.freifunk-wizard.nav" + local predecessor, successor = nav.get() +%> + <% if predecessor then %> + "> + Zurück + + <% end %> + +
+
+
+<% end %>