Verified Commit 9181ded2 authored by Štěpán Henek's avatar Štěpán Henek 🌩

guide integration: with fake messages

parent 6ba4b7aa
......@@ -199,6 +199,15 @@ def reboot():
def leave_guide():
current_state.backend.perform("web", "update_guide", {
"enabled": False,
def ping():
res = bottle.response.copy(cls=bottle.HTTPResponse)
res.content_type = 'application/json'
......@@ -231,6 +240,7 @@ def init_default_app(index, include_static=False):
app.route("/lang/<lang:re:\w{2}>", name="change_lang", callback=change_lang)
app.route("/logout", name="logout", callback=logout)
app.route("/reboot", name="reboot", callback=reboot)
app.route("/leave_guide", method="POST", name="leave_guide", callback=leave_guide)
if include_static:
app.route('/static/<filename:re:.*>', name="static", callback=static)
app.route("/js/<filename:re:.*>", name="render_js", callback=render_js)
......@@ -633,6 +633,10 @@ def index():
def config_page_get(page_name):
# redirect in case that guide is not passed
if and page_name not in
bottle.SimpleTemplate.defaults['active_config_page_key'] = page_name
ConfigPage = get_config_page(page_name)
config_page = ConfigPage()
# Foris - web administration interface for OpenWrt based on NETCONF
# Copyright (C) 2017 CZ.NIC, z.s.p.o. <>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <>.
from foris.utils.translators import _
class StandardMessages(object):
"password": [
"Welcome to Foris configuration. Bla bla bla"
"wan": [
"In order to access the internet you need to configure your WAN device. Bla bla bla"
"time": [
_("In order to verify TLS certificates validity your time has to be properly set. ..."),
"dns": [
_("To resolve ip addresses to hostnames ..."),
"password": [
_("Your password seems to be set. You may proceed to the next step"),
"wan": [
"You've configured your wan interface. "
"Try to run connection test to see whether it is working properly"
"time": [
"Your timezone seems to be set. Please make sure that the time is correct "
" because bla bla bla"
"dns": [
"You've updated your dns configuration. "
"Try to run connection test to see whether your dns is properly set."
"updater": [
_("To keep your software up-to-date you need to configure updater first."),
def get(step, current):
if current and step in StandardMessages.MESSAGES_CURRENT_MAP:
return StandardMessages.MESSAGES_CURRENT_MAP[step]
return StandardMessages.MESSAGES_MAP[step]
class Guide(object):
STEP_PASSWORD = "password"
STEP_WAN = "wan"
STEP_TIME = "time"
STEP_DNS = "dns"
STEP_UPDATER = "updater"
def __init__(self, backend_data):
self.enabled = backend_data["enabled"]
self.workflow = backend_data["workflow"]
self.current = self._get_current(backend_data["passed"])
if not self.current: # All required steps are passed -> disable guide
self.enabled = False
def _get_current(self, passed):
if self.workflow == Guide.WORKFLOW_STANDARD:
for step in Guide.STANDARD_STEPS:
if step not in passed:
return step
return None
raise NotImplementedError("unknown workflow %s" % self.workflow)
def available_tabs(self):
if self.workflow == Guide.WORKFLOW_STANDARD:
return Guide.STANDARD_STEPS[:Guide.STANDARD_STEPS.index(self.current) + 1]
raise NotImplementedError("unknown workflow %s" % self.workflow)
def is_available(self, step):
if not self.enabled:
return True
return step in self.available_tabs
def message(self, step=None):
if not self.enabled:
return None
if self.workflow == Guide.WORKFLOW_STANDARD:
step = step if step else self.current
return StandardMessages.get(step, step == self.current)
raise NotImplementedError("unknown workflow %s" % self.workflow)
......@@ -68,4 +68,7 @@ class BackendData(object):
# update whether password is set
# initialize guide
return, start_response)
......@@ -80,5 +80,10 @@ class ForisState(object):
logger.debug("setting password_set=%s" % password_set)
self.password_set = password_set
def update_guide(self, guide_data):
from import Guide
logger.debug("setting guide_data (%s)" % guide_data) = Guide(guide_data)
current_state = ForisState()
......@@ -119,6 +119,29 @@ body
text-align: center
vertical-align: middle
padding: 1em 1em 1em 1em
display: block
background-color: $message-color-info
color: white
font-weight: bold
text-transform: uppercase
text-align: right
background-color: #fff
color: $message-color-info
font-weight: bold
font-family: $base-font
display: inline
padding: 1em 1em 1em 1em
......@@ -26,7 +26,7 @@ input.grayed, input[disabled]
border: none
.wizard-form, .config-form, .maintenance-form, .dns-form
.wizard-form, .config-form, .maintenance-form
margin-bottom: 1em
......@@ -32,6 +32,23 @@
<div id="content-wrap">
<div id="content">
<div id="guide-box">
<p class="guide-title">{{ trans("foris guide") }}</p>
%for msg in
<p>{{ msg }}</p>
<div class="guide-buttons">
<form method="post" action="{{ url("leave_guide") }}">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
<button type="submit" name="target" class="button" value="save">{{ trans("Leave Guided Mode") }}</button>
%if != active_config_page_key:
<a class="button" href="{{ url("config_page", }}">{{ trans("Next step") }} ➡</a>
<div id="network-restart-notice" class="main-warning-notice">
<img src="{{ static("img/loader.gif") }}" alt="{{ trans("Network is restarting...") }}" title="{{ trans("Network is restarting...") }}">
<span>{{ trans("Your network is being restarted. Wait, please...") }}</span>
......@@ -61,11 +78,16 @@
%for slug, config_page, menu_tag in config_pages.menu_list():
<li{{! ' class="active"' if defined("active_config_page_key") and slug == active_config_page_key else "" }}>
<a href="{{ url("config_page", page_name=slug) }}">{{ trans(config_page.userfriendly_title) }}
<span title="{{ menu_tag["hint"]}}" style="{{"" if menu_tag["show"] else "display: none" }}" id="{{ slug }}_menu_tag" class="menu-tag">{{! menu_tag["text"] }}</span>
% show = menu_tag["show"] or and slug ==
<span title="{{ menu_tag["hint"]}}" style="{{"" if show else "display: none" }}" id="{{ slug }}_menu_tag" class="menu-tag">
{{ "⬅" if and slug == else menu_tag["text"] }}
......@@ -23,12 +23,15 @@
%if not contract_valid():
<p>{{! trans("In rare cases ISP's have improperly configured network which interferes with DNSSEC validation. If you experience problems with DNS, you can <strong>temporarily</strong> disable DNSSEC validation to determine the source of the problem. However, keep in mind that without DNSSEC validation, you are vulnerable to DNS spoofing attacks! Therefore we <strong>recommend keeping DNSSEC turned on</strong> and resolving the situation with your ISP as this is a serious flaw on their side.") }}</p>
<form id="main-form" class="dns-form" action="{{ request.fullpath }}" method="post" enctype="multipart/form-data" autocomplete="off" novalidate>
<form id="main-form" class="config-form" action="{{ request.fullpath }}" method="post" enctype="multipart/form-data" autocomplete="off" novalidate>
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
%for field in form.active_fields:
%include("_field.tpl", field=field)
<button type="submit" name="send" class="button">{{ trans("Save") }}</button>
<div class="form-buttons">
<a href="{{ request.fullpath }}" class="button grayed">{{ trans("Discard changes") }}</a>
<button type="submit" name="send" class="button">{{ trans("Save changes") }}</button>
<h2>{{ trans("Connection test") }}</h2>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment