Verified Commit 2dd8e464 authored by Štěpán Henek's avatar Štěpán Henek 🌩

Basic functions implemented

still missing:
  * correct sass/css style management
  * nicer design + maybe some charts
  * proper error handling (get_setting might failed when netmetr hasn't run yet)
  * translations
parent f2510728
This diff is collapsed.
# Foris netmetr plugin
# Copyright (C) 2017 CZ.NIC, z. s. p. o. <https://www.nic.cz>
#
# Foris is distributed under the terms of GNU General Public License v3.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import bottle
import os
from datetime import datetime
from foris import fapi
from foris.config import ConfigPageMixin, add_config_page
from foris.config_handlers import BaseConfigHandler
from foris.form import Checkbox
from foris.plugins import ForisPlugin
from foris.state import current_state
from foris.utils import messages, reverse
from foris.utils.translators import gettext_dummy as gettext, ugettext as _
class NetmetrPluginConfigHandler(BaseConfigHandler):
userfriendly_title = gettext("netmetr")
def get_form(self):
data = current_state.backend.perform("netmetr", "get_settings", {})
# init hours
for i in range(24):
data["hour_to_run_%d" % i] = False
# update the enabled
for e in data["hours_to_run"]:
data["hour_to_run_%d" % e] = True
if self.data:
# Update from post
data.update(self.data)
form = fapi.ForisForm("netmetr", data)
main = form.add_section(name="set_netmetr", title=_(self.userfriendly_title))
autostart_section = main.add_section(name="autostart", title=_("Autostart"))
autostart_section.add_field(
Checkbox, name="autostart_enabled", label=_("Autostart enabled"),
preproc=lambda val: bool(int(val)), hint=_("TBD")
)
hours = main.add_section(name="hours", title=_("Autostart times"))
for i in range(24):
hours.add_field(
Checkbox, name="hour_to_run_%d" % i, label="%02d:00" % i,
preproc=lambda val: bool(int(val)),
).requires("autostart_enabled", True)
def form_cb(data):
msg = {"autostart_enabled": data["autostart_enabled"]}
if data["autostart_enabled"]:
msg["hours_to_run"] = []
for i in range(24):
name = "hour_to_run_%d" % i
if name in data and data[name]:
msg["hours_to_run"].append(i)
current_state.backend.perform("netmetr", "update_settings", msg)
messages.success(_("Netmeter settings were updated."))
return "none", None
form.add_callback(form_cb)
return form
class NetmetrPluginPage(ConfigPageMixin, NetmetrPluginConfigHandler):
menu_order = 80
template = "netmetr_plugin/netmetr_plugin.tpl"
userfriendly_title = gettext("Netmetr")
def save(self, *args, **kwargs):
kwargs['no_messages'] = True # disable default messages
return super(NetmetrPluginPage, self).save(*args, **kwargs)
def _prepare_results(self, results):
results.sort(key=lambda x: x["time"], reverse=True)
for record in results:
record["time"] = datetime.fromtimestamp(record["time"]).strftime("%Y-%m-%d %H:%M:%S")
return results
def _prepare_render_args(self, args):
args['PLUGIN_NAME'] = NetmetrPlugin.PLUGIN_NAME
args['PLUGIN_STYLES'] = NetmetrPlugin.PLUGIN_STYLES
args['PLUGIN_STATIC_SCRIPTS'] = NetmetrPlugin.PLUGIN_STATIC_SCRIPTS
args['PLUGIN_DYNAMIC_SCRIPTS'] = NetmetrPlugin.PLUGIN_DYNAMIC_SCRIPTS
obtained = current_state.backend.perform("netmetr", "get_data")
args["status"] = obtained["status"]
args["results"] = self._prepare_results(obtained["performed_tests"])
def render(self, **kwargs):
self._prepare_render_args(kwargs)
return super(NetmetrPluginPage, self).render(**kwargs)
def call_ajax_action(self, action):
if action == "redownload":
bottle.response.set_header("Content-Type", "application/json")
return current_state.backend.perform("netmetr", "download_data", {})
elif action == "start":
bottle.response.set_header("Content-Type", "application/json")
return current_state.backend.perform("netmetr", "measure_and_download_data", {})
elif action == "get_data":
bottle.response.set_header("Content-Type", "text/html")
data = current_state.backend.perform("netmetr", "get_data", {})
sync_code = current_state.backend.perform("netmetr", "get_settings", {})["sync_code"]
return bottle.template(
"netmetr_plugin/_results",
results=self._prepare_results(data["performed_tests"]),
sync_code=sync_code,
)
raise ValueError("Unknown AJAX action.")
def _action_download_data(self):
current_state.backend.perform("netmetr", "download_data", {})
bottle.redirect(reverse("config_page", page_name="netmetr_plugin"))
def _action_measure_and_download_data(self):
current_state.backend.perform("netmetr", "measure_and_download_data", {})
bottle.redirect(reverse("config_page", page_name="netmetr_plugin"))
def call_action(self, action):
if bottle.request.method != 'POST':
messages.error("Wrong HTTP method.")
bottle.redirect(reverse("config_page", page_name="netmetr_plugin"))
if action == "redownload":
self._action_download_data()
elif action == "start":
self._action_measure_and_download_data()
raise bottle.HTTPError(404, "Unknown action.")
class NetmetrPlugin(ForisPlugin):
PLUGIN_NAME = "netmetr_plugin"
DIRNAME = os.path.dirname(os.path.abspath(__file__))
PLUGIN_STYLES = [
"css/netmetr_plugin.css"
]
PLUGIN_STATIC_SCRIPTS = [
]
PLUGIN_DYNAMIC_SCRIPTS = [
"netmetr_plugin.js"
]
def __init__(self, app):
super(NetmetrPlugin, self).__init__(app)
add_config_page("netmetr_plugin", NetmetrPluginPage, top_level=True)
Foris.watched_process = null;
Foris.update_data = function() {
$.get('{{ url("config_ajax", page_name="netmetr_plugin") }}', {action: "get_data"})
.done(function(response, status, xhr) {
if (xhr.status == 200) {
$("#netmetr-results").replaceWith(response); // replace the table
$("#start-trigger").show()
$("#redownload-trigger").show()
}
})
.fail(function(xhr) {
if (xhr.responseJSON && xhr.responseJSON.loggedOut && xhr.responseJSON.loginUrl) {
window.location.replace(xhr.responseJSON.loginUrl);
return;
}
});
};
Foris.WS["netmetr"] = function(msg) {
if (msg.data.async_id != Foris.watched_process) {
return;
}
switch(msg["action"]) {
case "download_data_finished":
if (msg.data.passed) {
$("#netmetr-control-status").text('{{ trans("Downloading...OK")}}');
Foris.update_data();
} else {
$("#netmetr-control-status").text('{{ trans("Downloading...FAILED")}}');
}
break;
case "measure_and_download_data_finished":
if (msg.data.passed) {
$("#netmetr-control-status").text('{{ trans("Testing...OK")}}');
$("#netmetr-control-progress").text('');
Foris.update_data();
} else {
$("#netmetr-control-status").text('{{ trans("Testing...FAILED")}}');
}
break;
case "measure_and_download_data_notification":
$("#netmetr-control-progress").text(msg.data.percent.toString() + "% " + msg.data.msg);
break;
}
};
$(document).ready(function() {
$("#redownload-trigger").click(function(e) {
e.preventDefault();
$.get('{{ url("config_ajax", page_name="netmetr_plugin") }}', {action: "redownload"})
.done(function(response) {
Foris.watched_process = response["async_id"];
$("#start-trigger").hide()
$("#redownload-trigger").hide()
$("#netmetr-control-status").text('{{ trans("Downloading...")}}');
});
});
$("#start-trigger").click(function(e) {
e.preventDefault();
$.get('{{ url("config_ajax", page_name="netmetr_plugin") }}', {action: "start"})
.done(function(response) {
Foris.watched_process = response["async_id"];
$("#start-trigger").hide()
$("#redownload-trigger").hide()
$("#netmetr-control-status").text('{{ trans("Testing...")}}');
$("#netmetr-control-progress").text("0%");
});
});
});
<div id="netmetr-results">
%if results:
<table id="netmetr-results-table">
<thead>
<tr><th>{{ trans("time") }}</th><th>{{ trans("download") }}</th><th>{{ trans("upload") }}</th><th>{{ trans("ping") }}</th><th>{{ trans("link") }}</th></tr>
</thead>
<tbody>
%for record in results:
<tr><td>{{ record["time"] }}</td><td>{{ record["speed_download"] }}</td><td>{{ record["speed_upload"] }}</td><td>{{ record["ping"] }}</td><td><a href="https://example.com/?sync_code={{ sync_code }}&test_uuid={{ record["test_uuid"]}}">{{ trans("Complete results") }}</a></td></tr>
%end
</tbody>
</table>
%else:
<p>{{ trans("No results found.") }}</p>
%end
</div>
%rebase("config/base.tpl", **locals())
<style>
#netmetr-results th {
padding: 3px;
text-align: center;
font-weight: bold;
}
#netmetr-results td {
padding: 3px;
}
</style>
<div id="page-netmetr-plugin" class="config-page">
%include("_messages.tpl")
<form action="{{ request.fullpath }}" class="config-form" method="post">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
<h3>{{ form.sections[0].sections[0].title }}</h3>
%for field in form.sections[0].sections[0].active_fields:
%include("_field.tpl", field=field)
%end
%if form.active_fields[0].field.get_value():
<br />
<h5>{{ form.sections[0].sections[1].title }}</h5>
%end
<div class="row">
%for field in form.sections[0].sections[1].active_fields:
<div style="text-align: center; display: inline-block; padding: 2px">
{{! field.label_tag }}
<br />
{{! field.render() }}
</div>
%end
</div>
<br />
<div class="form-buttons">
<button type="submit" name="send" class="button">{{ trans("Save") }}</button>
</div>
</form>
<h3>{{ trans("Controls") }}</h3>
<p id="netmetr-control-status"></p>
<p id="netmetr-control-progress"></p>
<form action="{{ url("config_action", page_name="netmetr_plugin", action="perform") }}" class="config-form" id="netmetr-controls" method="post">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
<button type="submit" name="action" id="redownload-trigger" value="redownload" class="button">{{ trans("Redownload data") }}</button>
<button type="submit" name="action" id="start-trigger" value="start" class="button">{{ trans("Start test") }}</button>
</form>
<h3>{{ trans("Results") }}</h3>
%include("netmetr_plugin/_results.tpl", results=results, sync_code=form._request_data["sync_code"])
</div>
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