def get_form(self): tls_form = ForisForm("tls", self.data, filter=ca_filter) maintenance_main = tls_form.add_section(name="tls_client", title=_( self.userfriendly_title)) maintenance_main.add_field( Textbox, name="client_name", label=_("Client name"), required=True, hint= _("The display name for the client. It must be shorter than 64 characters " "and must contain only alphanumeric characters, dots, dashes and " "underscores."), validators=[ RegExp(_("Client name is invalid."), client_name_regexp), LenRange(1, 63) ]) def maintenance_form_cb(data): client_name = data['client_name'] if new_client(client_name): messages.success( _("Request for creating a new client \"%s\" was succesfully submitted. " "Client token should be available for download in a minute." ) % client_name) else: messages.error( _("An error occurred when creating client \"%s\".") % client_name) return "none", None tls_form.add_callback(maintenance_form_cb) return tls_form
def save(self, *args, **kwargs): result = super(ProfileConfigPage, self).save(no_messages=True, *args, **kwargs) if self.form.callback_results["result"]: messages.success(_("Guide workflow was sucessfully set.")) else: messages.error(_("Failed to set guide workflow.")) return result
def save(self, *args, **kwargs): result = super(NetworksConfigPage, self).save(no_messages=True, *args, **kwargs) if self.form.callback_results["result"]: messages.success(_("Network configuration was sucessfully updated.")) else: messages.error(_("Unable to update your network configuration.")) return result
def _ajax_delete(self): controller_id = self._check_and_get_controller_id() res = current_state.backend.perform("subordinates", "del", {"controller_id": controller_id}) if res["result"]: return bottle.template( "config/_message.html.j2", message={ "classes": ["success"], "text": _("Subordinate '%(controller_id)s' was successfully deleted." ) % dict(controller_id=controller_id), }, template_adapter=bottle.Jinja2Template, ) else: return bottle.template( "config/_message.html.j2", message={ "classes": ["error"], "text": _("Failed to delete subordinate '%(controller_id)s'.") % dict(controller_id=controller_id), }, template_adapter=bottle.Jinja2Template, )
def get_form(self): data = current_state.backend.perform("data_collect", "get") if self.data and "enable" in self.data: data["enable"] = self.data["enable"] else: data["enable"] = data["agreed"] form = fapi.ForisForm("enable_collection", data) section = form.add_section( name="collection_toggle", title=_(self.userfriendly_title), ) section.add_field(Checkbox, name="enable", label=_("Enable data collection"), preproc=lambda val: bool(int(val))) def form_cb(data): data = current_state.backend.perform("data_collect", "set", {"agreed": data["enable"]}) return "save_result", data # store {"result": ...} to be used later... form.add_callback(form_cb) return form
def get_form(self): form = fapi.ForisForm("registration_check", self.data) main_section = form.add_section(name="check_email", title=_(self.userfriendly_title)) main_section.add_field(Email, name="email", label=_("Email")) def form_cb(data): data = current_state.backend.perform( "data_collect", "get_registered", { "email": data.get("email"), "language": current_state.language }) error = None registration_number = None url = None if data["status"] == "unknown": error = _("Failed to query the server.") elif data["status"] == "not_valid": error = _("Failed to verify the router's registration.") elif data["status"] in ["free", "foreign"]: url = data["url"] registration_number = data["registration_number"] return "save_result", { 'success': data["status"] not in ["unknown", "not_valid"], 'status': data["status"], 'error': error, 'url': url, 'registration_number': registration_number, } form.add_callback(form_cb) return form
def get_client_form(self, data=None): client_form = ForisForm("openvpn", data) main_section = client_form.add_section( name="name", title=None, ) main_section.add_field( Textbox, name="client_name", label=_("Client name"), required=True, hint= _("The display name for the client. It must be shorter than 64 characters " "and must contain only alphanumeric characters, dots, dashes and " "underscores."), validators=[ RegExp(_("Client name is invalid."), r'[a-zA-Z0-9_.-]+'), LenRange(1, 63) ]) def form_callback(data): current_state.backend.perform("openvpn", "generate_client", {"name": self.data['client_name']}) messages.success( _("Started to generate client '%(name)s' for the OpenVPN server." ) % dict(name=data['client_name'])) return bottle.redirect(reverse("config_page", page_name="openvpn")) client_form.add_callback(form_callback) return client_form
def get_form(self): form = fapi.ForisForm("create_and_upload", self.data) section = form.add_section( name="passwords", title=self.userfriendly_title, ) section.add_field( Password, name="password", label=_("Password"), required=True, validators=validators.LenRange(6, 128) ) section.add_field( Password, name="password_validation", label=_("Password (repeat)"), required=True, validators=validators.EqualTo( "password", "password_validation", _("Passwords are not equal.") ) ) def form_cb(data): res = current_state.backend.perform( "ssbackups", "set_password", {"password": base64.b64encode(data["password"].encode()).decode()} ) return "save_result", res # store {"result": ...} to be used later... form.add_callback(form_cb) return form
def _action_delete_ca(self): self._check_post() data = current_state.backend.perform("remote", "delete_ca") if data["result"]: messages.success(_("CA for remote access was sucessfully deleted.")) else: messages.error(_("Failed to delete CA for remote access.")) bottle.redirect(reverse("config_page", page_name="remote"))
class NuciTLS(YinElement): tag = "nuci-tls" NS_URI = "http://www.nic.cz/ns/router/nuci-tls" CLIENT_STATUS_ACTIVE = _("active") CLIENT_STATUS_REVOKED = _("revoked") CLIENT_STATUS_EXPIRED = _("expired") def __init__(self, clients, generating): super(NuciTLS, self).__init__() self.clients = clients self.generating = generating @staticmethod def from_element(element): generating = element.find(NuciTLS.qual_tag("generating")) is not None client_elements = element.findall(NuciTLS.qual_tag("client")) clients = {} for client_el in client_elements: name = client_el.find(NuciTLS.qual_tag("name")).text status = client_el.find(NuciTLS.qual_tag("status")).text clients[name] = {'name': name, 'status': status} return NuciTLS(clients, generating) @property def key(self): return "nuci-tls" @staticmethod def rpc_reset_ca(background=True): rpc_el = ET.Element(NuciTLS.qual_tag("reset-CA")) if background: ET.SubElement(rpc_el, NuciTLS.qual_tag("background")) return rpc_el @staticmethod def rpc_new_client(name, background=True): rpc_el = ET.Element(NuciTLS.qual_tag("new-client")) name_el = ET.SubElement(rpc_el, NuciTLS.qual_tag("name")) name_el.text = name if background: ET.SubElement(rpc_el, NuciTLS.qual_tag("background")) return rpc_el @staticmethod def rpc_revoke_client(name): rpc_el = ET.Element(NuciTLS.qual_tag("revoke-client")) name_el = ET.SubElement(rpc_el, NuciTLS.qual_tag("name")) name_el.text = name return rpc_el @staticmethod def rpc_get_token(name): rpc_el = ET.Element(NuciTLS.qual_tag("get-token")) name_el = ET.SubElement(rpc_el, NuciTLS.qual_tag("name")) name_el.text = name return rpc_el
def make_form(self, data: typing.Optional[dict]) -> fapi.ForisForm: backend_data = current_state.backend.perform( "wifi", "get_settings", controller_id=self.controller_id ) form_data = self.convert_data_from_backend_to_form(backend_data) if data: form_data.update(data) used_bands = [] for field_name, band in [(k, v) for k, v in form_data.items() if k.endswith("hwmode")]: # radioX-hwmode => X radio_number = field_name.split("-", 1)[0][len("radio"):] radio_enabled = form_data.get(f"radio{radio_number}-device_enabled", False) if (isinstance(radio_enabled, bool) and radio_enabled) or radio_enabled == "1": used_bands.append(band) wifi_form = fapi.ForisForm("wifi", form_data) # display conflict message when two wifis are using the same band wifi_form.band_conflict = not (len(used_bands) == len(set(used_bands))) wifi_form.add_section( name="wifi", title=_("Wi-Fi"), description=_( "If you want to use your router as a Wi-Fi access point, enable Wi-Fi " "here and fill in an SSID (the name of the access point) and a " "corresponding password. You can then set up your mobile devices, " "using the QR code available within the form." ), ) # Add wifi section wifi_section = wifi_form.add_section(name="wifi_settings", title=_("Wi-Fi settings")) for idx, device in enumerate(backend_data["devices"]): prefix = WifiEditForm.prefixed(device["id"], "") device_form_data = { k[len(prefix) :]: v for k, v in form_data.items() if k.startswith(prefix) } # prefix removed self._prepare_device_fields( wifi_section, device, device_form_data, len(backend_data["devices"]) - 1 == idx ) def form_cb(data): update_data = self.convert_data_from_form_to_backend( data, [e["id"] for e in backend_data["devices"]] ) res = current_state.backend.perform( "wifi", "update_settings", update_data, controller_id=self.controller_id ) return "save_result", res wifi_form.add_callback(form_cb) return wifi_form
def save(self, *args, **kwargs): no_messages = kwargs.pop("no_messages", False) result = super(ConfigPageMixin, self).save(*args, **kwargs) if no_messages: return result if result: messages.success(_("Configuration was successfully saved.")) else: messages.warning(_("There were some errors in your input.")) return result
def save(self, *args, **kwargs): super().save(no_messages=True, *args, **kwargs) result = self.form.callback_results.get('result', False) if result: messages.success(_("Configuration was successfully saved.")) else: messages.error( _("Failed to update emulated services. Note that you might need to wait till " "ucollect is properly installed.")) return result
def save(self, *args, **kwargs): super(MaintenanceConfigPage, self).save(no_messages=True, *args, **kwargs) result = self.form.callback_results.get('result') if result: messages.success(_("Configuration was successfully restored. " "Note that a reboot will be required to apply restored " "configuration.")) else: messages.warning(_("Failed to restore the backup from the provided file.")) return result
def _action_save_notifications(self): if bottle.request.method != 'POST': messages.error(_("Wrong HTTP method.")) bottle.redirect(reverse("config_page", page_name="maintenance")) handler = notifications.NotificationsHandler(request.POST.decode()) if handler.save(): messages.success(_("Configuration was successfully saved.")) bottle.redirect(reverse("config_page", page_name="maintenance")) messages.warning(_("There were some errors in your input.")) return super(MaintenanceConfigPage, self).render(notifications_form=handler.form)
def _action_save_notifications(self): if bottle.request.method != "POST": messages.error(_("Wrong HTTP method.")) bottle.redirect(reverse("config_page", page_name="maintenance")) handler = notifications.NotificationsHandler(bottle.request.POST.decode()) if handler.save(): messages.success(_("Configuration was successfully saved.")) bottle.redirect(reverse("config_page", page_name="maintenance")) messages.warning(_("There were some errors in your input.")) return super(MaintenanceConfigPage, self).render(notifications_form=handler.form)
def maintenance_form_cb(data): client_name = data['client_name'] if new_client(client_name): messages.success( _("Request for creating a new client \"%s\" was succesfully submitted. " "Client token should be available for download in a minute." ) % client_name) else: messages.error( _("An error occurred when creating client \"%s\".") % client_name) return "none", None
def _action_toggle_collecting(self): if bottle.request.method != 'POST': messages.error(_("Wrong HTTP method.")) bottle.redirect(reverse("config_page", page_name="data_collect")) handler = CollectionToggleHandler(bottle.request.POST.decode()) if handler.save(): messages.success(_("Configuration was successfully saved.")) bottle.redirect(reverse("config_page", page_name="data_collect")) messages.warning(_("There were some errors in your input.")) return super().render(collection_toggle_form=handler.form)
def _action_delete_ca(self): """Call RPC to delete the CA of the openvpn server :return: redirect to plugin's main page """ res = current_state.backend.perform("openvpn", "delete_ca") if res["result"]: messages.success(_("The OpenVPN CA was successfully deleted.")) else: messages.success(_("Failed to delete the OpenVPN CA.")) return bottle.redirect(reverse("config_page", page_name="openvpn"))
def _action_reset_ca(self): """Call RPC for resetting the CA and redirect back. :return: redirect to plugin's main page """ if reset_ca(): messages.success( _("Reset of the certification authority was successfully submitted." )) else: messages.error(_("An error occurred when trying to reset the CA.")) bottle.redirect(reverse("config_page", page_name="tls"))
def _action_revoke(self): """Handle POST requesting revoking client certificate config :return: response with token with appropriate HTTP headers """ res = current_state.backend.perform("openvpn", "revoke", {"id": self.data['revoke-client']}) if res["result"]: messages.success( _("The client certificate was successfully revoked.")) else: messages.error(_("Failed to revoke the client certificate.")) return bottle.redirect(reverse("config_page", page_name="openvpn"))
def prepare_message(results: dict) -> dict: if results["result"]: message = { "classes": ["success"], "text": _("Wi-Fi settings were successfully updated."), } else: message = { "classes": ["error"], "text": _("Failed to update Wi-Fi settings.") } return message
def _action_reset(self): if bottle.request.method != "POST": messages.error(_("Wrong HTTP method.")) bottle.redirect(reverse("config_page", page_name="wifi")) data = current_state.backend.perform("wifi", "reset") if "result" in data and data["result"] is True: messages.success(_("Wi-Fi reset was successful.")) else: messages.error(_("Failed to perform Wi-Fi reset.")) bottle.redirect(reverse("config_page", page_name="wifi"))
def save(self, *args, **kwargs): super(MaintenanceConfigPage, self).save(no_messages=True, *args, **kwargs) result = self.form.callback_results.get("result") if result: messages.success( _( "Configuration was successfully restored. " "Note that a reboot will be required to apply restored " "configuration." ) ) else: messages.warning(_("Failed to restore the backup from the provided file.")) return result
def save(self, *args, **kwargs): super(SubordinatesSetupPage, self).save(no_messages=True, *args, **kwargs) data = self.form.callback_results if data["result"]: messages.success( _("Token was successfully added and client '%(controller_id)s' " "should be visible in a moment.") % dict(controller_id=data["controller_id"])) else: messages.error(_("Failed to add token.")) return data["result"]
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= _("Measuring will start about selected hour (time is no exact for load distribution)" )) 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(_("Netmetr settings were updated.")) return "none", None form.add_callback(form_cb) return form
class Workflow(object): TITLES = { WORKFLOW_OLD: _("Old"), WORKFLOW_MIN: _("Minimal"), WORKFLOW_ROUTER: _("Router"), WORKFLOW_BRIDGE: _("Local Server"), WORKFLOW_UNSET: _("Unset"), } DESCRIPTIONS = { WORKFLOW_UNSET: _("The workflow wasn't set yet."), WORKFLOW_OLD: _("Workflow for older devices and older turris OS versions (before 4.0)." ), WORKFLOW_MIN: _("Just set your password and you are ready to go. " "This workflow is aimed to more advanced users who intend not to use the web gui. " ), WORKFLOW_ROUTER: _("After you finish this workflow your device will be able to act as a fully " "functional router. It assumes that you want to have more or less standard " "network setup."), WORKFLOW_BRIDGE: _("This workflow will help you to setup your device to act as a local server. " "It means that the device will provide some kind of service to other devices " "within your local network (e.g. act as a network attached storage)." ), } def __init__(self, workflow, current, recommended): """ Create object which describes a guide workflow :type current: bool :type recommended: bool """ if workflow not in WORKFLOWS: raise KeyError("Workflow '%s' was not found." % workflow) self.name = workflow self.title = Workflow.TITLES[workflow] self.description = Workflow.DESCRIPTIONS[workflow] self.current = current self.recommended = recommended @property def img(self): return "img/workflow-%s.svg" % self.name
def __init__(self, low, high): self.error_msg = _("This value should be between %(low)s and %(high)s." ) % dict(low=low, high=high) self._low = low self._high = high super(FloatRange, self).__init__(self.error_msg) self.js_validator_params = "[%s,%s]" % (low, high)
def __init__(self): pattern = r"^([01][0-9]|2[0-3]):([0-5][0-9])$" super(Time, self).__init__(_("This is not valid time in HH:MM format."), pattern) self.js_validator = ("pattern", pattern) self.extra_data["parsley-error-message"] = self.msg
def __init__(self, low, high): self._low = low self._high = high super(ByteLenRange, self).__init__( _("Length must be from %(low)s to %(high)s characters.") % dict(low=low, high=high)) self.js_validator_params = "[%s,%s]" % (low, high)
def __init__(self, low, high): self._low = low self._high = high super(InRange, self).__init__( _("Not in a valid range %(low).1f - %(high).1f.") % dict(low=low, high=high) ) self.js_validator_params = "[%.1f,%.1f]" % (low, high)
def top_index(): session = bottle.request.environ["foris.session"] if bottle.request.method == "POST": next = bottle.request.POST.get("next", None) login(next, session) # if login passes it will redirect to a proper page # otherwise it contains next parameter messages.error(_("The password you entered was not valid.")) response.status = 403 else: next = bottle.request.GET.get("next", None) if not current_state.password_set: # auto login if no password is set if session.is_anonymous: session.recreate() session["user_authenticated"] = True session.save() if session.get("user_authenticated"): login_redirect() return dict( luci_path="//%(host)s/%(path)s" % { "host": bottle.request.get_header("host"), "path": "cgi-bin/luci" }, next=next, )
def get_generate_token_form(self, data=None): generate_token_form = fapi.ForisForm("generate_remote_token", data) token_section = generate_token_form.add_section("generate_token", title=None) token_section.add_field( Textbox, name="name", label=_("Token name"), required=True, hint=_( "The display name for the token. It must be shorter than 64 characters " "and must contain only alphanumeric characters, dots, dashes and " "underscores." ), validators=[RegExp(_("Token name is invalid."), r"[a-zA-Z0-9_.-]+"), LenRange(1, 63)], ) return generate_token_form
def __init__(self, low, high): self._low = low self._high = high super(ByteLenRange, self).__init__( _("Length must be from %(low)s to %(high)s characters.") % dict(low=low, high=high) ) self.js_validator_params = "[%s,%s]" % (low, high)
def get_form(self): data = current_state.backend.perform("sample", "get_slices") if self.data: # Update from post (used when the form is updated via ajax) data.update(self.data) form = fapi.ForisForm("sample", data) section = form.add_section( name="main_section", title=self.userfriendly_title, ) # _() translates the string immediatelly # it is also used for detecting translations during foris_make_messages cmd section.add_field( Number, name="slices", label=_("Number of slices"), required=True, validators=validators.InRange(2, 15) ) def form_cb(data): res = current_state.backend.perform( "sample", "set_slices", {"slices": int(data["slices"])}) return "save_result", res # store {"result": ...} to be used in SamplePluginPage save() method form.add_callback(form_cb) return form
def __init__(self, low, high): self._low = low self._high = high super(InRange, self).__init__( _("Not in a valid range %(low).1f - %(high).1f.") % dict(low=low, high=high)) self.js_validator_params = "[%.1f,%.1f]" % (low, high)
def top_index(): session = bottle.request.environ["foris.session"] if bottle.request.method == "POST": next = bottle.request.POST.get("next", None) login(next, session) # if login passes it will redirect to a proper page # otherwise it contains next parameter messages.error(_("The password you entered was not valid.")) response.status = 403 else: next = bottle.request.GET.get("next", None) if not current_state.password_set: # auto login if no password is set if session.is_anonymous: session.recreate() session["user_authenticated"] = True session.save() if session.get("user_authenticated"): login_redirect() return dict( luci_path="//%(host)s/%(path)s" % {"host": bottle.request.get_header("host"), "path": "cgi-bin/luci"}, next=next, )
def config_action_post(page_name, action): bottle.SimpleTemplate.defaults["active_config_page_key"] = page_name bottle.Jinja2Template.defaults["active_config_page_key"] = page_name ConfigPage = get_config_page(page_name) config_page = ConfigPage(request.POST.decode()) if request.is_xhr: if request.POST.pop("_update", None): # if update was requested, just render the page - otherwise handle actions as usual return config_page.render(is_xhr=True) # check if the button click wasn't any sub-action subaction = request.POST.pop("action", None) if subaction: return config_action_post(page_name, subaction) try: result = config_page.call_action(action) try: if not result: bottle.redirect(reverse("config_page", page_name=page_name)) except TypeError: # raised by Validator - could happen when the form is posted with wrong fields messages.error(_("Configuration could not be saved due to an internal error.")) logger.exception("Error when saving form.") logger.warning("Form not saved.") return result except ValueError: raise bottle.HTTPError(404, "Unknown action.")
def get_form(self): maintenance_form = fapi.ForisForm("maintenance", self.data) maintenance_main = maintenance_form.add_section( name="restore_backup", title=_(self.userfriendly_title) ) maintenance_main.add_field(File, name="backup_file", label=_("Backup file"), required=True) def maintenance_form_cb(data): data = current_state.backend.perform( "maintain", "restore_backup", {"backup": base64.b64encode(data["backup_file"].file.read()).decode("utf-8")}, ) return "save_result", {"result": data["result"]} maintenance_form.add_callback(maintenance_form_cb) return maintenance_form
def __init__(self, low, high): self.error_msg = _("This value should be between %(low)s and %(high)s.") % dict( low=low, high=high ) self._low = low self._high = high super(FloatRange, self).__init__(self.error_msg) self.js_validator_params = "[%s,%s]" % (low, high)
def get_token_id_form(self, data=None): token_id_form = fapi.ForisForm("token_id_form", data) token_section = token_id_form.add_section("token_id_section", title=None) token_section.add_field( Textbox, name="token_id", label="", required=True, validators=[RegExp(_("Token id is invalid."), r"([a-zA-Z0-9][a-zA-Z0-9])+")], ) token_section.add_field( Textbox, name="name", label=_("Token name"), required=False, validators=[RegExp(_("Token name is invalid."), r"[a-zA-Z0-9_.-]+"), LenRange(1, 63)], ) return token_id_form
def make_notification_title(notification): """ Helper function for creating of human-readable notification title. :param notification: notification to create title for :return: translated string with notification title """ notification_titles = {"news": _("News"), "update": _("Update"), "error": _("Error")} # minor abuse of gettext follows... locale_date = translate_datetime( datetime.strptime(notification["created_at"], "%Y-%m-%dT%H:%M:%S") ) return _("%(notification)s from %(created_at)s") % dict( notification=notification_titles.get(notification["severity"], _("Notification")), created_at=locale_date, )
def prepare_approval_item_message(approval_item, show_operation=True): if approval_item["op"] == "install": return ((_("Install") + " ") if show_operation else "") + u"%s (%s)" % ( approval_item["name"], approval_item["new_ver"], ) elif approval_item["op"] == "remove": return ((_("Uninstall") + " ") if show_operation else "") + u"%s" % (approval_item["name"],) elif approval_item["op"] == "upgrade": return ((_("Upgrade") + " ") if show_operation else "") + "%s (%s)" % ( approval_item["name"], approval_item["new_ver"], ) elif approval_item["op"] == "downgrade": return ((_("Downgrade") + " ") if show_operation else "") + "%s (%s)" % ( approval_item["name"], approval_item["new_ver"], )
def get_menu_tag(cls): if current_state.updater_is_running: return { "show": current_state.updater_is_running, "hint": _("Updater is running"), "text": u"<i class='fas fa-sync rotate'></i>", } else: return ConfigPageMixin.get_menu_tag_static(cls)
def make_form(self, data: typing.Optional[dict]) -> fapi.ForisForm: backend_data = current_state.backend.perform( "wifi", "get_settings", controller_id=self.controller_id ) form_data = self.convert_data_from_backend_to_form(backend_data) if data: form_data.update(data) wifi_form = fapi.ForisForm("wifi", form_data) wifi_form.add_section( name="wifi", title=_("Wi-Fi"), description=_( "If you want to use your router as a Wi-Fi access point, enable Wi-Fi " "here and fill in an SSID (the name of the access point) and a " "corresponding password. You can then set up your mobile devices, " "using the QR code available within the form." ), ) # Add wifi section wifi_section = wifi_form.add_section(name="wifi_settings", title=_("Wi-Fi settings")) for idx, device in enumerate(backend_data["devices"]): prefix = WifiEditForm.prefixed(device["id"], "") device_form_data = { k[len(prefix) :]: v for k, v in form_data.items() if k.startswith(prefix) } # prefix removed self._prepare_device_fields( wifi_section, device, device_form_data, len(backend_data["devices"]) - 1 == idx ) def form_cb(data): update_data = self.convert_data_from_form_to_backend( data, [e["id"] for e in backend_data["devices"]] ) res = current_state.backend.perform( "wifi", "update_settings", update_data, controller_id=self.controller_id ) return "save_result", res wifi_form.add_callback(form_cb) return wifi_form
def get_form(self): finished_form = fapi.ForisForm("guide_finished", {}) finished_form.add_section(name="guide_finished", title=_(self.userfriendly_title)) def guide_finished_cb(data): res = current_state.backend.perform("web", "update_guide", {"enabled": False}) return "save_result", res # store {"result": ...} to be used later... finished_form.add_callback(guide_finished_cb) return finished_form
def _action_test_notifications(self): if bottle.request.method != "POST": messages.error(_("Wrong HTTP method.")) bottle.redirect(reverse("config_page", page_name="maintenance")) data = current_state.backend.perform( "router_notifications", "create", { "msg": "_(This is a testing notification. Please ignore me.)", "severity": "news", "immediate": True, }, ) if data["result"]: messages.success(_("Testing message was sent, please check your inbox.")) else: messages.error( _("Sending of the testing message failed, your configuration is possibly wrong.") ) bottle.redirect(reverse("config_page", page_name="maintenance"))
def save(self, *args, **kwargs): result = super(UpdaterConfigPage, self).save(no_messages=True, *args, **kwargs) target = self.form.callback_results.get("target", None) if target in ["deny", "grant"]: result = self.form.callback_results["result"] if result: if target == "grant": messages.success(_("Update was approved.")) elif target == "deny": messages.success(_("Update was postponed.")) else: if target == "grant": messages.error(_("Failed to approve the update.")) elif target == "deny": messages.error(_("Failed to postpone the update.")) return result if result: messages.success( _( "Configuration was successfully saved. Selected " "packages should be installed or removed shortly." ) ) else: messages.warning(_("There were some errors in your input.")) return result
def save(self, *args, **kwargs): result = super(PasswordConfigPage, self).save(no_messages=True, *args, **kwargs) wrong_old_password = self.form.callback_results.get("wrong_old_password", False) system_password_no_error = self.form.callback_results.get("system_password_no_error", None) foris_password_no_error = self.form.callback_results.get("foris_password_no_error", None) compromised = self.form.callback_results.get("compromised") if compromised: messages.error( _( "The password you've entered has been compromised. " "It appears %(count)d times in '%(list)s' list." ) % dict(count=compromised["count"], list=compromised["list"]) ) return result if wrong_old_password: messages.error(_("Old password you entered was not valid.")) return result if system_password_no_error is not None: if system_password_no_error: messages.success(_("System password was successfully saved.")) else: messages.error(_("Failed to save system password.")) if foris_password_no_error is not None: if foris_password_no_error: messages.success(_("Foris password was successfully saved.")) else: messages.error(_("Failed to save Foris password.")) return result
def get_form(self): data = copy.deepcopy(self.backend_data) if self.data: # Update from post data.update(self.data) networks_form = fapi.ForisForm("networks", self.data) ports_section = networks_form.add_section( name="set_ports", title=_(self.userfriendly_title) ) checkboxes = [] for kind in ["wan", "lan", "guest", "none"]: checkboxes += [(e["id"], e["id"]) for e in self.backend_data["networks"][kind]] ports_section.add_field(MultiCheckbox, name="wan", args=checkboxes, multifield=True) ports_section.add_field(MultiCheckbox, name="lan", args=checkboxes, multifield=True) ports_section.add_field(MultiCheckbox, name="guest", args=checkboxes, multifield=True) ports_section.add_field(MultiCheckbox, name="none", args=checkboxes, multifield=True) ports_section.add_field(Checkbox, name="ssh_on_wan", default=False, required=False) ports_section.add_field(Checkbox, name="http_on_wan", default=False, required=False) ports_section.add_field(Checkbox, name="https_on_wan", default=False, required=False) def networks_form_cb(data): wan = data.get("wan", []) lan = data.get("lan", []) guest = data.get("guest", []) none = data.get("none", []) ssh_on_wan = bool(data.get("ssh_on_wan", "0")) http_on_wan = bool(data.get("http_on_wan", "0")) https_on_wan = bool(data.get("https_on_wan", "0")) result = current_state.backend.perform( "networks", "update_settings", { "firewall": { "ssh_on_wan": ssh_on_wan, "http_on_wan": http_on_wan, "https_on_wan": https_on_wan, }, "networks": {"lan": lan, "wan": wan, "guest": guest, "none": none}, }, ) return "save_result", result networks_form.add_callback(networks_form_cb) return networks_form
def config_page_post(page_name): bottle.SimpleTemplate.defaults["active_config_page_key"] = page_name bottle.Jinja2Template.defaults["active_config_page_key"] = page_name ConfigPage = get_config_page(page_name) config_page = ConfigPage(request.POST.decode()) if request.is_xhr: if request.POST.pop("_update", None): # if update was requested, just render the page - otherwise handle actions as usual pass else: config_page.save() return config_page.render(is_xhr=True) try: if config_page.save(): bottle.redirect(request.fullpath) except TypeError: # raised by Validator - could happen when the form is posted with wrong fields messages.error(_("Configuration could not be saved due to an internal error.")) logger.exception("Error when saving form.") logger.warning("Form not saved.") return config_page.render(active_config_page_key=page_name)
def get_form(self): data = { "enabled": self.backend_data["enabled"], "port": self.backend_data["port"], "wan_access": self.backend_data["wan_access"], } if self.data: # Update from post data.update(self.data) form = fapi.ForisForm("remote", data) config_section = form.add_section(name="set_remote", title=_(self.userfriendly_title)) config_section.add_field(Checkbox, name="enabled", label=_("Enable remote access")) config_section.add_field( Checkbox, name="wan_access", label=_("Accessible via WAN"), hint=_( "If this option is check the device in the WAN network will be able to connect " "to the configuration interface. Otherwise only devices on LAN will be able to " "access the configuration interface." ), ).requires("enabled", True) config_section.add_field( Number, name="port", label=_("Port"), hint=_("A port which will be opened for the remote configuration " "of this device."), validator=[InRange(1, 2 ** 16 - 1)], default=11884, ).requires("enabled", True) def form_callback(data): msg = {"enabled": data["enabled"]} if msg["enabled"]: msg["port"] = int(data["port"]) msg["wan_access"] = data["wan_access"] res = current_state.backend.perform("remote", "update_settings", msg) res["enabled"] = msg["enabled"] return "save_result", res # store {"result": ...} to be used later... form.add_callback(form_callback) return form
def translate_datetime(datetime_instance, default="%Y/%m/%d %H:%M:%S"): """ Tries to "translate" the datetime. This functions should handle e.g. conversions between US / EU date format according to localized translation. So these formats were added to be translated. Unfortunatelly some translators used non-asci characters to format the date. That would raise an exception and this function handles that by adding a fallback format. :param datetime_instance: date to be formatted :type datetime_instance: datetime.datetime :param default: default format :type default: str :returns: formatted date :rtype: str """ try: return datetime_instance.strftime(_("%Y/%m/%d %H:%M:%S")) except UnicodeEncodeError: # Unicode characters in translated format -> fallback to default return datetime_instance.strftime(default)
def __init__(self): super(IPv4Netmask, self).__init__(_("Not a valid IPv4 netmask address."))
def __init__(self): super(IPv4, self).__init__(_("Not a valid IPv4 address."))
def __init__(self): super(NotEmpty, self).__init__(_("This field is required."))
def __init__(self): super(Duid, self).__init__(_("Duid is not valid.")) self.reg_exp = re.compile(r"^([0-9a-fA-F][0-9a-fA-F]){4}([0-9a-fA-F][0-9a-fA-F])*$")