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 get_form(self): data = copy.deepcopy(self.backend_data) data["enabled"] = "1" if data["enabled"] else "0" data["approval_status"] = data["approval_settings"]["status"] if "delay" in data["approval_settings"]: data["approval_delay"] = data["approval_settings"]["delay"] for userlist in [e for e in data['user_lists'] if not e["hidden"]]: data["install_%s" % userlist["name"]] = userlist["enabled"] for lang in data["languages"]: data["language_%s" % lang["code"]] = lang["enabled"] if self.data: # Update from post data.update(self.data) self.updater_enabled = True if data["enabled"] == "1" else False self.approval_setting_status = data["approval_status"] self.approval_setting_delay = data.get("approval_delay", self.APPROVAL_DEFAULT_DELAY) form = fapi.ForisForm("updater", data) main_section = form.add_section( name="main", title=_(self.userfriendly_title), description=_("Updater is a service that keeps all TurrisOS " "software up to date. Apart from the standard " "installation, you can optionally select bundles of " "additional software that'd be installed on the " "router. This software can be selected from the " "following list. " "Please note that only software that is part of " "TurrisOS or that has been installed from a package " "list is maintained by Updater. Software that has " "been installed manually or using opkg is not " "affected.")) main_section.add_field( Radio, name="enabled", label=_("I agree"), default="1", args=(("1", _("Use automatic updates (recommended)")), ("0", _("Turn automatic updates off"))), ) approval_section = main_section.add_section( name="approvals", title=_("Update approvals")) approval_section.add_field( RadioSingle, name=UpdaterHandler.APPROVAL_NO, group="approval_status", label=_("Automatic installation"), hint=_("Updates will be installed without user's intervention."), default=data["approval_status"], ) approval_section.add_field( RadioSingle, name=UpdaterHandler.APPROVAL_TIMEOUT, group="approval_status", label=_("Delayed updates"), hint=_("Updates will be installed with an adjustable delay. " "You can also approve them manually."), default=data["approval_status"], ) approval_section.add_field( Number, name="approval_delay", validators=[validators.InRange(1, 24 * 7)], default=UpdaterHandler.APPROVAL_DEFAULT_DELAY, min=1, max=24 * 7, required=True, ).requires(UpdaterHandler.APPROVAL_TIMEOUT, UpdaterHandler.APPROVAL_TIMEOUT).requires( UpdaterHandler.APPROVAL_NO, UpdaterHandler.APPROVAL_TIMEOUT).requires( UpdaterHandler.APPROVAL_NEEDED, UpdaterHandler.APPROVAL_TIMEOUT) approval_section.add_field( RadioSingle, name=UpdaterHandler.APPROVAL_NEEDED, group="approval_status", label=_("Update approval needed"), hint= _("You have to approve the updates, otherwise they won't be installed." ), default=data["approval_status"], ) package_lists_main = main_section.add_section( name="select_package_lists", title=None, ) for userlist in [e for e in data['user_lists'] if not e["hidden"]]: package_lists_main.add_field(Checkbox, name="install_%s" % userlist["name"], label=userlist["title"], hint=userlist["msg"]).requires( "enabled", "1") language_lists_main = main_section.add_section( name="select_languages", title=_( "If you want to use other language than English you can select it from the " "following list:")) for lang in data["languages"]: language_lists_main.add_field(Checkbox, name="language_%s" % lang["code"], label=lang["code"].upper()) if self.backend_data["approval"]["present"]: # field for hidden approval current_approval_section = main_section.add_section( name="current_approval", title="") current_approval_section.add_field( Hidden, name="approval-id", default=self.backend_data["approval"]["hash"]) # this will be filled according to action main_section.add_field(Hidden, name="target") def form_cb(data): data["enabled"] = True if data["enabled"] == "1" else False if data["enabled"] and data["target"] == "save": if data[self.APPROVAL_NEEDED] == self.APPROVAL_NEEDED: data["approval_settings"] = { "status": self.APPROVAL_NEEDED } elif data[self.APPROVAL_TIMEOUT] == self.APPROVAL_TIMEOUT: data["approval_settings"] = { "status": self.APPROVAL_TIMEOUT } data["approval_settings"]["delay"] = int( data["approval_delay"]) elif data[self.APPROVAL_NO] == self.APPROVAL_NO: data["approval_settings"] = {"status": self.APPROVAL_NO} if self.agreed_collect: data["enabled"] = True languages = [ k[9:] for k, v in data.items() if v and k.startswith("language_") ] user_lists = [ k[8:] for k, v in data.items() if v and k.startswith("install_") ] # merge with enabled hidden user lists user_lists += [ e["name"] for e in self.backend_data["user_lists"] if e["hidden"] and e["enabled"] ] res = current_state.backend.perform( "updater", "update_settings", { "enabled": True, "approval_settings": data["approval_settings"], "user_lists": user_lists, "languages": languages, }) elif data["enabled"] and data["target"] in ["grant", "deny"]: res = current_state.backend.perform( "updater", "resolve_approval", { "hash": data["approval-id"], "solution": data["target"] }) else: res = current_state.backend.perform("updater", "update_settings", { "enabled": False, }) res["target"] = data["target"] return "save_result", res form.add_callback(form_cb) return form
def get_form(self): # WAN wan_form = fapi.ForisForm("wan", self.data, filter=create_config_filter( "network", "smrtd", "ucollect")) wan_main = wan_form.add_section( name="set_wan", title=_(self.userfriendly_title), description= _("Here you specify your WAN port settings. Usually, you can leave this " "options untouched unless instructed otherwise by your internet service " "provider. Also, in case there is a cable or DSL modem connecting your " "router to the network, it is usually not necessary to change this " "setting.")) WAN_DHCP = "dhcp" WAN_STATIC = "static" WAN_PPPOE = "pppoe" WAN_OPTIONS = ( (WAN_DHCP, _("DHCP (automatic configuration)")), (WAN_STATIC, _("Static IP address (manual configuration)")), (WAN_PPPOE, _("PPPoE (for DSL bridges, Modem Turris, etc.)")), ) WAN6_NONE = "none" WAN6_DHCP = "dhcpv6" WAN6_STATIC = "static" WAN6_OPTIONS = ( (WAN6_DHCP, _("DHCPv6 (automatic configuration)")), (WAN6_STATIC, _("Static IP address (manual configuration)")), ) if not self.hide_no_wan: WAN6_OPTIONS = ((WAN6_NONE, _("Disable IPv6")), ) + WAN6_OPTIONS # protocol wan_main.add_field(Dropdown, name="proto", label=_("IPv4 protocol"), nuci_path="uci.network.wan.proto", args=WAN_OPTIONS, default=WAN_DHCP) # static ipv4 wan_main.add_field(Textbox, name="ipaddr", label=_("IP address"), nuci_path="uci.network.wan.ipaddr", required=True, validators=validators.IPv4())\ .requires("proto", WAN_STATIC) wan_main.add_field(Textbox, name="netmask", label=_("Network mask"), nuci_path="uci.network.wan.netmask", required=True, validators=validators.IPv4Netmask())\ .requires("proto", WAN_STATIC) wan_main.add_field(Textbox, name="gateway", label=_("Gateway"), nuci_path="uci.network.wan.gateway", validators=validators.IPv4(), required=True)\ .requires("proto", WAN_STATIC) def extract_dns_item(dns_option, index, default=None): if isinstance(dns_option, List): dns_list = [e.content for e in dns_option.children] elif isinstance(dns_option, Option): dns_list = dns_option.value.split(" ") else: return default # Server with higher priority should be last dns_list.reverse() try: return dns_list[index] except IndexError: return default # DNS servers wan_main.add_field(Textbox, name="dns1", label=_("DNS server 1"), nuci_path="uci.network.wan.dns", nuci_preproc=lambda val: extract_dns_item(val, 0), validators=validators.AnyIP(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it."))\ .requires("proto", WAN_STATIC) wan_main.add_field(Textbox, name="dns2", label=_("DNS server 2"), nuci_path="uci.network.wan.dns", nuci_preproc=lambda val: extract_dns_item(val, 1), validators=validators.AnyIP(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it."))\ .requires("proto", WAN_STATIC) # xDSL settings wan_main.add_field(Textbox, name="username", label=_("PAP/CHAP username"), nuci_path="uci.network.wan.username")\ .requires("proto", WAN_PPPOE) wan_main.add_field(Textbox, name="password", label=_("PAP/CHAP password"), nuci_path="uci.network.wan.password")\ .requires("proto", WAN_PPPOE) # IPv6 configuration wan_main.add_field(Dropdown, name="wan6_proto", label=_("IPv6 protocol"), args=WAN6_OPTIONS, default=WAN6_NONE, nuci_path="uci.network.wan6.proto") wan_main.add_field(Textbox, name="ip6addr", label=_("IPv6 address"), nuci_path="uci.network.wan6.ip6addr", validators=validators.IPv6Prefix(), hint=_("IPv6 address and prefix length for WAN interface, " "e.g. 2001:db8:be13:37da::1/64"), required=True)\ .requires("wan6_proto", WAN6_STATIC) wan_main.add_field(Textbox, name="ip6gw", label=_("IPv6 gateway"), validators=validators.IPv6(), nuci_path="uci.network.wan6.ip6gw")\ .requires("wan6_proto", WAN6_STATIC) wan_main.add_field(Textbox, name="ip6prefix", label=_("IPv6 prefix"), validators=validators.IPv6Prefix(), nuci_path="uci.network.wan6.ip6prefix", hint=_("Address range for local network, " "e.g. 2001:db8:be13:37da::/64"))\ .requires("wan6_proto", WAN6_STATIC) # enable SMRT settings only if smrtd config is present has_smrtd = wan_form.nuci_config.find_child("uci.smrtd") is not None if has_smrtd: wan_main.add_field(Hidden, name="has_smrtd", default="1") wan_main.add_field(Checkbox, name="use_smrt", label=_("Use Modem Turris"), nuci_path="uci.smrtd.global.enabled", nuci_preproc=lambda val: bool(int(val.value)), hint=_("Modem Turris (aka SMRT - Small Modem for Router Turris), " "a simple ADSL/VDSL modem designed specially for router " "Turris. Enable this option if you have Modem Turris " "connected to your router."))\ .requires("proto", WAN_PPPOE) def get_smrtd_param(param_name): """Helper function for getting SMRTd params for "connections" list.""" def wrapped(conn_list): # internet connection must be always first list element vlan_id, vpi, vci = ( conn_list.children[0].content.split(" ") if conn_list else (None, None, None)) if param_name == "VPI": return vpi elif param_name == "VCI": return vci elif param_name == "VLAN": return vlan_id raise ValueError("Unknown SMRTd connection parameter.") return wrapped def get_smrtd_vlan(data): """Helper function for getting VLAN number from Uci data.""" ifname = data.find_child("uci.network.wan.ifname") if ifname: ifname = ifname.value matches = re.match("%s.(\d+)" % self.wan_ifname, ifname) if matches: return matches.group(1) connections = data.find_child("uci.smrtd.%s.connections" % self.wan_ifname) result = get_smrtd_param("VLAN")(connections) return result # 802.1Q VLAN number is 12-bit, 0x0 and 0xFFF reserved wan_main.add_field(Textbox, name="smrt_vlan", label=_("xDSL VLAN number"), nuci_preproc=get_smrtd_vlan, validators=[validators.PositiveInteger(), validators.InRange(1, 4095)], hint=_("VLAN number for your internet connection. Your ISP might " "have provided you this number. If you have VPI and VCI " "numbers instead, leave this field empty, a default value " "will be used automatically."))\ .requires("use_smrt", True) vpi_vci_validator = validators.RequiredWithOtherFields( ("smrt_vpi", "smrt_vci"), _("Both VPI and VCI must be filled or both must be empty.")) wan_main.add_field( Textbox, name="smrt_vpi", label=_("VPI"), nuci_path="uci.smrtd.%s.connections" % self.wan_ifname, nuci_preproc=get_smrtd_param("VPI"), validators=[validators.PositiveInteger(), validators.InRange(0, 255), vpi_vci_validator], hint=_("Virtual Path Identifier (VPI) is a parameter that you might have received " "from your ISP. If you have a VLAN number instead, leave this field empty. " "You need to fill in both VPI and VCI together.") ) \ .requires("use_smrt", True) wan_main.add_field( Textbox, name="smrt_vci", label=_("VCI"), nuci_path="uci.smrtd.%s.connections" % self.wan_ifname, nuci_preproc=get_smrtd_param("VCI"), validators=[validators.PositiveInteger(), validators.InRange(32, 65535), vpi_vci_validator], hint=_("Virtual Circuit Identifier (VCI) is a parameter that you might have " "received from your ISP. If you have a VLAN number instead, leave this " "field empty. You need to fill in both VPI and VCI together.") )\ .requires("use_smrt", True) # custom MAC wan_main.add_field( Checkbox, name="custom_mac", label=_("Custom MAC address"), nuci_path="uci.network.wan.macaddr", nuci_preproc=lambda val: bool(val.value), hint=_( "Useful in cases, when a specific MAC address is required by " "your internet service provider.")) wan_main.add_field(Textbox, name="macaddr", label=_("MAC address"), nuci_path="uci.network.wan.macaddr", validators=validators.MacAddress(), hint=_("Separator is a colon, for example 00:11:22:33:44:55"), required=True)\ .requires("custom_mac", True) def wan_form_cb(data): uci = Uci() network = Config("network") uci.add(network) wan = Section("wan", "interface") network.add(wan) wan.add(Option("proto", data['proto'])) if data['custom_mac'] is True: wan.add(Option("macaddr", data['macaddr'])) else: wan.add_removal(Option("macaddr", None)) ucollect_ifname = self.wan_ifname if data['proto'] == WAN_PPPOE: wan.add(Option("username", data['username'])) wan.add(Option("password", data['password'])) wan.add(Option("ipv6", data.get("wan6_proto") is not WAN6_NONE)) ucollect_ifname = "pppoe-wan" elif data['proto'] == WAN_STATIC: wan.add(Option("ipaddr", data['ipaddr'])) wan.add(Option("netmask", data['netmask'])) wan.add(Option("gateway", data['gateway'])) dns_list = List("dns") dns2 = data.get("dns2", None) if dns2: dns_list.add(Value(0, dns2)) dns1 = data.get("dns1", None) if dns1: dns_list.add(Value( 1, dns1)) # dns with higher priority should be added last if not dns_list.children: wan.add_removal(dns_list) else: wan.add_replace(dns_list) # IPv6 configuration wan6 = Section("wan6", "interface") network.add(wan6) wan6.add(Option("ifname", "@wan")) wan6.add(Option("proto", data['wan6_proto'])) if data.get("wan6_proto") == WAN6_STATIC: wan6.add(Option("ip6addr", data['ip6addr'])) wan6.add(Option("ip6gw", data['ip6gw'])) wan6.add(Option("ip6prefix", data['ip6prefix'])) else: wan6.add_removal(Option("ip6addr", None)) wan6.add_removal(Option("ip6gw", None)) wan6.add_removal(Option("ip6prefix", None)) if has_smrtd: smrtd = Config("smrtd") uci.add(smrtd) smrt_vlan = data.get("smrt_vlan") use_smrt = data.get("use_smrt", False) wan_if = Section(self.wan_ifname, "interface") smrtd.add(wan_if) wan_if.add(Option("name", self.wan_ifname)) if use_smrt: if not smrt_vlan: # "proprietary" number - and also a common VLAN ID in CZ smrt_vlan = "848" self.wan_ifname += ".%s" % smrt_vlan vpi, vci = data.get("smrt_vpi"), data.get("smrt_vci") connections = List("connections") if vpi and vci: wan_if.add(connections) connections.add( Value(1, "%s %s %s" % (smrt_vlan, vpi, vci))) elif use_smrt: wan_if.add_removal(connections) smrtd_global = Section("global", "global") smrtd.add(smrtd_global) smrtd_global.add(Option("enabled", use_smrt)) # set correct ifname for WAN - must be changed when disabling SMRT wan.add(Option("ifname", self.wan_ifname)) # set interface for ucollect to listen on interface_if_name = None ucollect_interface0 = wan_form.nuci_config.find_child( "uci.ucollect.@interface[0]") if ucollect_interface0: interface_if_name = ucollect_interface0.name ucollect = Config("ucollect") uci.add(ucollect) interface = Section(interface_if_name, "interface", True) ucollect.add(interface) interface.add(Option("ifname", ucollect_ifname)) return "edit_config", uci wan_form.add_callback(wan_form_cb) return wan_form
def get_form(self): notifications_form = fapi.ForisForm( "notifications", self.data, filter=create_config_filter("user_notify")) notifications = notifications_form.add_section( name="notifications", title=_("Notifications settings")) # notifications settings notifications.add_field(Checkbox, name="enable_smtp", label=_("Enable notifications"), nuci_path="uci.user_notify.smtp.enable", nuci_preproc=lambda val: bool(int(val.value)), default=False) notifications.add_field( Radio, name="use_turris_smtp", label=_("SMTP provider"), default="0", args=(("1", _("Turris")), ("0", _("Custom"))), nuci_path="uci.user_notify.smtp.use_turris_smtp", hint=_("If you set SMTP provider to \"Turris\", the servers provided to members of the " "Turris project would be used. These servers do not require any additional " "settings. If you want to set your own SMTP server, please select \"Custom\" " "and enter required settings."))\ .requires("enable_smtp", True) notifications.add_field( Textbox, name="to", label=_("Recipient's email"), nuci_path="uci.user_notify.smtp.to", nuci_preproc=lambda x: " ".join( map(lambda value: value.content, x.children)), hint= _("Email address of recipient. Separate multiple addresses by spaces." ), required=True).requires("enable_smtp", True) # sender's name for CZ.NIC SMTP only notifications.add_field( Textbox, name="sender_name", label=_("Sender's name"), hint=_("Name of the sender - will be used as a part of the " "sender's email address before the \"at\" sign."), nuci_path="uci.user_notify.smtp.sender_name", validators=[validators.RegExp(_("Sender's name can contain only " "alphanumeric characters, dots " "and underscores."), r"^[0-9a-zA-Z_\.-]+$")], required=True )\ .requires("enable_smtp", True)\ .requires("use_turris_smtp", "1") SEVERITY_OPTIONS = ( (1, _("Reboot is required")), (2, _("Reboot or attention is required")), (3, _("Reboot or attention is required or update was installed")), ) notifications.add_field(Dropdown, name="severity", label=_("Importance"), nuci_path="uci.user_notify.notifications.severity", nuci_preproc=lambda val: int(val.value), args=SEVERITY_OPTIONS, default=1)\ .requires("enable_smtp", True) notifications.add_field(Checkbox, name="news", label=_("Send news"), hint=_("Send emails about new features."), nuci_path="uci.user_notify.notifications.news", nuci_preproc=lambda val: bool(int(val.value)), default=True)\ .requires("enable_smtp", True) # SMTP settings (custom server) smtp = notifications_form.add_section(name="smtp", title=_("SMTP settings")) smtp.add_field(Email, name="from", label=_("Sender address (From)"), hint=_("This is the address notifications are sent from."), nuci_path="uci.user_notify.smtp.from", required=True)\ .requires("enable_smtp", True)\ .requires("use_turris_smtp", "0") smtp.add_field(Textbox, name="server", label=_("Server address"), nuci_path="uci.user_notify.smtp.server", required=True)\ .requires("enable_smtp", True)\ .requires("use_turris_smtp", "0") smtp.add_field(Number, name="port", label=_("Server port"), nuci_path="uci.user_notify.smtp.port", validators=[validators.PositiveInteger()], required=True) \ .requires("enable_smtp", True)\ .requires("use_turris_smtp", "0") SECURITY_OPTIONS = ( ("none", _("None")), ("ssl", _("SSL/TLS")), ("starttls", _("STARTTLS")), ) smtp.add_field(Dropdown, name="security", label=_("Security"), nuci_path="uci.user_notify.smtp.security", args=SECURITY_OPTIONS, default="none") \ .requires("enable_smtp", True).requires("use_turris_smtp", "0") smtp.add_field(Textbox, name="username", label=_("Username"), nuci_path="uci.user_notify.smtp.username")\ .requires("enable_smtp", True)\ .requires("use_turris_smtp", "0") smtp.add_field(Password, name="password", label=_("Password"), nuci_path="uci.user_notify.smtp.password")\ .requires("enable_smtp", True)\ .requires("use_turris_smtp", "0") # reboot time reboot = notifications_form.add_section( name="reboot", title=_("Automatic restarts after software update")) reboot.add_field( Number, name="delay", label=_("Delay (days)"), hint=_( "Number of days that must pass between receiving the request " "for restart and the automatic restart itself."), nuci_path="uci.user_notify.reboot.delay", validators=[ validators.PositiveInteger(), validators.InRange(0, 10) ], required=True) reboot.add_field( Time, name="reboot_time", label=_("Reboot time"), hint=_("Time of day of automatic reboot in HH:MM format."), nuci_path="uci.user_notify.reboot.time", validators=[validators.Time()], required=True) def notifications_form_cb(data): uci = Uci() user_notify = Config("user_notify") uci.add(user_notify) smtp = Section("smtp", "smtp") user_notify.add(smtp) smtp.add(Option("enable", data['enable_smtp'])) reboot = Section("reboot", "reboot") user_notify.add(reboot) reboot.add(Option("time", data['reboot_time'])) reboot.add(Option("delay", data['delay'])) if data['enable_smtp']: smtp.add(Option("use_turris_smtp", data['use_turris_smtp'])) if data['use_turris_smtp'] == "0": smtp.add(Option("server", data['server'])) smtp.add(Option("port", data['port'])) smtp.add(Option("username", data['username'])) smtp.add(Option("password", data['password'])) smtp.add(Option("security", data['security'])) smtp.add(Option("from", data['from'])) else: smtp.add(Option("sender_name", data['sender_name'])) to = List("to") for i, to_item in enumerate(data['to'].split(" ")): if to_item: to.add(Value(i, to_item)) smtp.add_replace(to) # notifications section notifications = Section("notifications", "notifications") user_notify.add(notifications) notifications.add(Option("severity", data['severity'])) notifications.add(Option("news", data['news'])) return "edit_config", uci notifications_form.add_callback(notifications_form_cb) return notifications_form
def get_form(self): data = WanHandler._convert_backend_data_to_form_data(self.backend_data) if self.data: # Update from post data.update(self.data) # WAN wan_form = fapi.ForisForm("wan", data) wan_main = wan_form.add_section( name="set_wan", title=_(self.userfriendly_title), description= _("Here you specify your WAN port settings. Usually, you can leave these " "options untouched unless instructed otherwise by your internet service " "provider. Also, in case there is a cable or DSL modem connecting your " "router to the network, it is usually not necessary to change this " "setting."), ) WAN_DHCP = "dhcp" WAN_STATIC = "static" WAN_PPPOE = "pppoe" WAN_OPTIONS = ( (WAN_DHCP, _("DHCP (automatic configuration)")), (WAN_STATIC, _("Static IP address (manual configuration)")), (WAN_PPPOE, _("PPPoE (for DSL bridges, Modem Turris, etc.)")), ) WAN6_NONE = "none" WAN6_DHCP = "dhcpv6" WAN6_STATIC = "static" WAN6_6TO4 = "6to4" WAN6_6IN4 = "6in4" WAN6_OPTIONS = ( (WAN6_DHCP, _("DHCPv6 (automatic configuration)")), (WAN6_STATIC, _("Static IP address (manual configuration)")), (WAN6_6TO4, _("6to4 (public IPv4 address required)")), (WAN6_6IN4, _("6in4 (public IPv4 address required)")), ) if not self.hide_no_wan: WAN6_OPTIONS = ((WAN6_NONE, _("Disable IPv6")), ) + WAN6_OPTIONS # protocol wan_main.add_field(Dropdown, name="proto", label=_("IPv4 protocol"), args=WAN_OPTIONS, default=WAN_DHCP) # static ipv4 wan_main.add_field( Textbox, name="ipaddr", label=_("IP address"), required=True, validators=validators.IPv4(), ).requires("proto", WAN_STATIC) wan_main.add_field( Textbox, name="netmask", label=_("Network mask"), required=True, validators=validators.IPv4Netmask(), ).requires("proto", WAN_STATIC) wan_main.add_field(Textbox, name="gateway", label=_("Gateway"), required=True, validators=validators.IPv4()).requires( "proto", WAN_STATIC) wan_main.add_field( Textbox, name="hostname", label=_("DHCP hostname"), validators=validators.Domain(), hint=_("Hostname which will be provided to DHCP server."), ).requires("proto", WAN_DHCP) # DNS servers wan_main.add_field( Textbox, name="ipv4_dns1", label=_("DNS server 1 (IPv4)"), validators=validators.IPv4(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it."), ).requires("proto", WAN_STATIC) wan_main.add_field( Textbox, name="ipv4_dns2", label=_("DNS server 2 (IPv4)"), validators=validators.IPv4(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it."), ).requires("proto", WAN_STATIC) # xDSL settings wan_main.add_field( Textbox, name="username", label=_("PAP/CHAP username"), required=True, ).requires("proto", WAN_PPPOE) wan_main.add_field( PasswordWithHide, name="password", label=_("PAP/CHAP password"), required=True, ).requires("proto", WAN_PPPOE) # IPv6 configuration wan_main.add_field( Dropdown, name="wan6_proto", label=_("IPv6 protocol"), args=WAN6_OPTIONS, default=WAN6_NONE, ) wan_main.add_field( Textbox, name="ip6addr", label=_("IPv6 address"), validators=validators.IPv6Prefix(), required=True, hint=_("IPv6 address and prefix length for WAN interface, " "e.g. 2001:db8:be13:37da::1/64"), ).requires("wan6_proto", WAN6_STATIC) wan_main.add_field( Textbox, name="ip6gw", label=_("IPv6 gateway"), validators=validators.IPv6(), required=True, ).requires("wan6_proto", WAN6_STATIC) wan_main.add_field( Textbox, name="ip6prefix", label=_("IPv6 prefix"), validators=validators.IPv6Prefix(), hint=_("Address range for local network, " "e.g. 2001:db8:be13:37da::/64"), ).requires("wan6_proto", WAN6_STATIC) # DNS servers wan_main.add_field( Textbox, name="ipv6_dns1", label=_("DNS server 1 (IPv6)"), validators=validators.IPv6(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it."), ).requires("wan6_proto", WAN6_STATIC) wan_main.add_field( Textbox, name="ipv6_dns2", label=_("DNS server 2 (IPv6)"), validators=validators.IPv6(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it."), ).requires("wan6_proto", WAN6_STATIC) wan_main.add_field( Textbox, name="ip6duid", label=_("Custom DUID"), validators=validators.Duid(), placeholder=self.status_data["last_seen_duid"], hint=_("DUID which will be provided to the DHCPv6 server."), ).requires("wan6_proto", WAN6_DHCP) wan_main.add_field( Textbox, name="6to4_ipaddr", label=_("Public IPv4"), validators=validators.IPv4(), hint= _("In order to use 6to4 protocol, you might need to specify your public IPv4 " "address manually (e.g. when your WAN interface has a private address which " "is mapped to public IP)."), placeholder=_("use autodetection"), required=False, ).requires("wan6_proto", WAN6_6TO4) wan_main.add_field( Textbox, name="6in4_server_ipv4", label=_("Provider IPv4"), validators=validators.IPv4(), hint= _("This address will be used as a endpoint of the tunnel on the provider's side." ), required=True, ).requires("wan6_proto", WAN6_6IN4) wan_main.add_field( Textbox, name="6in4_ipv6_prefix", label=_("Routed IPv6 prefix"), validators=validators.IPv6Prefix(), hint=_("IPv6 addresses which will be routed to your network."), required=True, ).requires("wan6_proto", WAN6_6IN4) wan_main.add_field( Number, name="6in4_mtu", label=_("MTU"), validators=validators.InRange(1280, 1500), hint=_("Maximum Transmission Unit in the tunnel (in bytes)."), required=True, default="1480", ).requires("wan6_proto", WAN6_6IN4) wan_main.add_field( Checkbox, name="6in4_dynamic_enabled", label=_("Dynamic IPv4 handling"), hint=_( "Some tunnel providers allow you to have public dynamic IPv4. " "Note that you need to fill in some extra fields to make it work." ), default=False, ).requires("wan6_proto", WAN6_6IN4) wan_main.add_field( Textbox, name="6in4_tunnel_id", label=_("Tunnel ID"), validators=validators.NotEmpty(), hint=_( "ID of your tunnel which was assigned to you by the provider." ), required=True, ).requires("6in4_dynamic_enabled", True) wan_main.add_field( Textbox, name="6in4_username", label=_("Username"), validators=validators.NotEmpty(), hint= _("Username which will be used to provide credentials to your tunnel provider." ), required=True, ).requires("6in4_dynamic_enabled", True) wan_main.add_field( Textbox, name="6in4_key", label=_("Key"), validators=validators.NotEmpty(), hint= _("Key which will be used to provide credentials to your tunnel provider." ), required=True, ).requires("6in4_dynamic_enabled", True) # custom MAC wan_main.add_field( Checkbox, name="custom_mac", label=_("Custom MAC address"), hint=_( "Useful in cases, when a specific MAC address is required by " "your internet service provider."), ) wan_main.add_field( Textbox, name="macaddr", label=_("MAC address"), validators=validators.MacAddress(), required=True, hint=_( "Colon is used as a separator, for example 00:11:22:33:44:55"), ).requires("custom_mac", True) def wan_form_cb(data): backend_data = WanHandler._convert_form_data_to_backend_data(data) res = current_state.backend.perform("wan", "update_settings", backend_data) return "save_result", res # store {"result": ...} to be used later... wan_form.add_callback(wan_form_cb) return wan_form
def get_form(self): data = {} data["mode"] = self.backend_data["mode"] data["router_ip"] = self.backend_data["mode_managed"]["router_ip"] data["router_netmask"] = self.backend_data["mode_managed"]["netmask"] data["router_dhcp_enabled"] = self.backend_data["mode_managed"][ "dhcp"]["enabled"] data["router_dhcp_start"] = self.backend_data["mode_managed"]["dhcp"][ "start"] data["router_dhcp_limit"] = self.backend_data["mode_managed"]["dhcp"][ "limit"] data["router_dhcp_leasetime"] = self.backend_data["mode_managed"]["dhcp"]["lease_time"] \ // (60 * 60) data["client_proto_4"] = self.backend_data["mode_unmanaged"][ "lan_type"] data["client_ip_4"] = self.backend_data["mode_unmanaged"][ "lan_static"]["ip"] data["client_netmask_4"] = self.backend_data["mode_unmanaged"][ "lan_static"]["netmask"] data["client_gateway_4"] = self.backend_data["mode_unmanaged"][ "lan_static"]["gateway"] dns1 = self.backend_data["mode_unmanaged"]["lan_static"].get("dns1") if dns1: data["client_dns1_4"] = dns1 dns2 = self.backend_data["mode_unmanaged"]["lan_static"].get("dns2") if dns2: data["client_dns2_4"] = dns2 data["client_hostname_4"] = self.backend_data["mode_unmanaged"][ "lan_dhcp"].get("hostname", "") if self.data: # Update from post data.update(self.data) lan_form = fapi.ForisForm( "lan", data, validators=[ validators.DhcpRangeValidator( 'router_netmask', 'router_dhcp_start', 'router_dhcp_limit', gettext( "<strong>DHCP start</strong> and <strong>DHCP max leases</strong> " "does not fit into <strong>Network netmask</strong>!"), [ lambda data: data['mode'] != 'managed', lambda data: not data['router_dhcp_enabled'], ]) ]) lan_main = lan_form.add_section( name="set_lan", title=_(self.userfriendly_title), description= _("This section contains settings for the local network (LAN). The provided" " defaults are suitable for most networks. <br><strong>Note:</strong> If " "you change the router IP address, all computers in LAN, probably " "including the one you are using now, will need to obtain a <strong>new " "IP address</strong> which does <strong>not</strong> happen <strong>" "immediately</strong>. It is recommended to disconnect and reconnect all " "LAN cables after submitting your changes to force the update. The next " "page will not load until you obtain a new IP from DHCP (if DHCP enabled)" " and you might need to <strong>refresh the page</strong> in your " "browser.")) lan_main.add_field( Dropdown, name="mode", label=_("LAN mode"), args=[ ("managed", _("Router")), ("unmanaged", _("Computer")), ], hint= _("Router mode means that this devices manages the LAN " "(acts as a router, can assing IP addresses, ...). " "Computer mode means that this device acts as a client in this network. " "It acts in a similar way as WAN, but it has opened ports for configuration " "interface and other services. "), default="managed", ) # managed options lan_main.add_field( Textbox, name="router_ip", label=_("Router IP address"), validators=validators.IPv4(), hint=_("Router's IP address in the inner network.")).requires( "mode", "managed") lan_main.add_field( Textbox, name="router_netmask", label=_("Network netmask"), validators=validators.IPv4Netmask(), hint=_("Network mask of the inner network.")).requires( "mode", "managed") lan_main.add_field( Checkbox, name="router_dhcp_enabled", label=_("Enable DHCP"), preproc=lambda val: bool(int(val)), default=True, hint=_( "Enable this option to automatically assign IP addresses to " "the devices connected to the router.")).requires( "mode", "managed") lan_main.add_field( Number, name="router_dhcp_start", label=_("DHCP start"), ).requires("router_dhcp_enabled", True) lan_main.add_field( Number, name="router_dhcp_limit", label=_("DHCP max leases"), ).requires("router_dhcp_enabled", True) lan_main.add_field(Number, name="router_dhcp_leasetime", label=_("Lease time (hours)"), validators=[validators.InRange(1, 7 * 24) ]).requires("router_dhcp_enabled", True) # unmanaged options LAN_DHCP = "dhcp" LAN_STATIC = "static" LAN_NONE = "none" LAN_OPTIONS = ( (LAN_DHCP, _("DHCP (automatic configuration)")), (LAN_STATIC, _("Static IP address (manual configuration)")), (LAN_NONE, _("Don't connect this device to LAN")), ) lan_main.add_field(Dropdown, name="client_proto_4", label=_("IPv4 protocol"), args=LAN_OPTIONS, default=LAN_DHCP).requires("mode", "unmanaged") # unmanaged static lan_main.add_field(Textbox, name="client_ip_4", label=_("IPv4 address"), required=True, validators=validators.IPv4()).requires( "client_proto_4", LAN_STATIC) lan_main.add_field(Textbox, name="client_netmask_4", label=_("Network mask"), required=True, validators=validators.IPv4Netmask()).requires( "client_proto_4", LAN_STATIC) lan_main.add_field( Textbox, name="client_gateway_4", label=_("Gateway"), required=True, validators=validators.IPv4(), ).requires("client_proto_4", LAN_STATIC) lan_main.add_field( Textbox, name="client_dns1_4", label=_("DNS server 1 (IPv4)"), validators=validators.IPv4(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it.")).requires( "client_proto_4", LAN_STATIC) lan_main.add_field( Textbox, name="client_dns2_4", label=_("DNS server 2 (IPv4)"), validators=validators.IPv4(), hint=_("DNS server address is not required as the built-in " "DNS resolver is capable of working without it.")).requires( "client_proto_4", LAN_STATIC) # unamanaged dhcp lan_main.add_field( Textbox, name="client_hostname_4", label=_("DHCP hostname"), validators=validators.Domain(), hint=_( "Hostname which will be provided to DHCP server.")).requires( "client_proto_4", LAN_DHCP) def lan_form_cb(data): msg = {"mode": data["mode"]} if msg["mode"] == "managed": dhcp = { "enabled": data["router_dhcp_enabled"], } if dhcp["enabled"]: dhcp["start"] = int(data["router_dhcp_start"]) dhcp["limit"] = int(data["router_dhcp_limit"]) dhcp["lease_time"] = int( data.get("router_dhcp_leasetime", 12)) * 60 * 60 msg["mode_managed"] = { "router_ip": data["router_ip"], "netmask": data["router_netmask"], "dhcp": dhcp, } elif data["mode"] == "unmanaged": msg["mode_unmanaged"] = { "lan_type": data["client_proto_4"], } if data["client_proto_4"] == "static": msg["mode_unmanaged"]["lan_static"] = { "ip": data["client_ip_4"], "netmask": data["client_netmask_4"], "gateway": data["client_gateway_4"], } dns1 = data.get("client_dns1_4") if dns1: msg["mode_unmanaged"]["lan_static"]["dns1"] = dns1 dns2 = data.get("client_dns2_4") if dns2: msg["mode_unmanaged"]["lan_static"]["dns2"] = dns2 elif data["client_proto_4"] == "dhcp": hostname = data.get("client_hostname_4") msg["mode_unmanaged"]["lan_dhcp"] = { "hostname": hostname } if hostname else {} res = current_state.backend.perform("lan", "update_settings", msg) return "save_result", res # store {"result": ...} to be used later... lan_form.add_callback(lan_form_cb) return lan_form
def get_form(self): data = {} data["guest_enabled"] = self.backend_data["enabled"] data["guest_ipaddr"] = self.backend_data["ip"] data["guest_netmask"] = self.backend_data["netmask"] data["guest_dhcp_enabled"] = self.backend_data["dhcp"]["enabled"] data["guest_dhcp_start"] = self.backend_data["dhcp"]["start"] data["guest_dhcp_limit"] = self.backend_data["dhcp"]["limit"] data["guest_dhcp_leasetime"] = self.backend_data["dhcp"]["lease_time"] // 60 // 60 data["guest_qos_enabled"] = self.backend_data["qos"]["enabled"] data["guest_qos_download"] = self.backend_data["qos"]["download"] data["guest_qos_upload"] = self.backend_data["qos"]["upload"] if self.data: # Update from post data.update(self.data) guest_form = fapi.ForisForm( "guest", data, validators=[ validators.DhcpRangeValidator( "guest_netmask", "guest_dhcp_start", "guest_dhcp_limit", gettext( "<strong>DHCP start</strong> and <strong>DHCP max leases</strong> " "does not fit into <strong>Guest network netmask</strong>!" ), [ lambda data: not data.get("guest_enabled"), lambda data: not data.get("guest_dhcp_enabled"), ], ), validators.DhcpRangeRouterIpValidator( "guest_ipaddr", "guest_netmask", "guest_dhcp_start", "guest_dhcp_limit", gettext( "<strong>Router IP</strong> should not be within DHCP range " "defined by <strong>DHCP start</strong> and <strong>DHCP max leases " "</strong>" ), [ lambda data: not data.get("guest_dhcp_enabled"), lambda data: not data.get("guest_enabled"), ], ), ], ) guest_network_section = guest_form.add_section( name="guest_network", title=_(self.userfriendly_title), description=_( "Guest network is used for <a href='%(url)s'>guest Wi-Fi</a>. It is separated " "from your ordinary LAN. Devices connected to this network are allowed " "to access the internet, but are not allowed to access the configuration " "interface of this device nor the devices in LAN." ) % dict(url=reverse("config_page", page_name="wifi")), ) guest_network_section.add_field( Checkbox, name="guest_enabled", label=_("Enable guest network"), default=False ) guest_network_section.add_field( Textbox, name="guest_ipaddr", label=_("Router IP in guest network"), default=DEFAULT_GUEST_IP, validators=validators.IPv4(), hint=_( "Router's IP address in the guest network. It is necessary that " "the guest network IPs are different from other networks " "(LAN, WAN, VPN, etc.)." ), ).requires("guest_enabled", True) guest_network_section.add_field( Textbox, name="guest_netmask", label=_("Guest network netmask"), default=DEFAULT_GUEST_MASK, validators=validators.IPv4Netmask(), hint=_("Network mask of the guest network."), ).requires("guest_enabled", True) guest_network_section.add_field( Checkbox, name="guest_dhcp_enabled", label=_("Enable DHCP"), preproc=lambda val: bool(int(val)), default=True, hint=_( "Enable this option to automatically assign IP addresses to " "the devices connected to the router." ), ).requires("guest_enabled", True) guest_network_section.add_field( Textbox, name="guest_dhcp_start", label=_("DHCP start") ).requires("guest_dhcp_enabled", True) guest_network_section.add_field( Textbox, name="guest_dhcp_limit", label=_("DHCP max leases") ).requires("guest_dhcp_enabled", True) guest_network_section.add_field( Textbox, name="guest_dhcp_leasetime", label=_("Lease time (hours)"), validators=[validators.InRange(1, 7 * 24)], ).requires("guest_dhcp_enabled", True) guest_network_section.add_field( Checkbox, name="guest_qos_enabled", label=_("Guest Lan QoS"), hint=_( "This option enables you to set a bandwidth limit for the guest network, " "so that your main network doesn't get slowed-down by it." ), ).requires("guest_enabled", True) guest_network_section.add_field( Number, name="guest_qos_download", label=_("Download (kb/s)"), validators=[validators.PositiveInteger()], hint=_("Download speed in guest network (in kilobits per second)."), default=1024, ).requires("guest_qos_enabled", True) guest_network_section.add_field( Number, name="guest_qos_upload", label=_("Upload (kb/s)"), validators=[validators.PositiveInteger()], hint=_("Upload speed in guest network (in kilobits per second)."), default=1024, ).requires("guest_qos_enabled", True) def guest_form_cb(data): if data["guest_enabled"]: msg = { "enabled": data["guest_enabled"], "ip": data["guest_ipaddr"], "netmask": data["guest_netmask"], "dhcp": {"enabled": data["guest_dhcp_enabled"]}, "qos": {"enabled": data["guest_qos_enabled"]}, } if data["guest_dhcp_enabled"]: msg["dhcp"]["start"] = int(data["guest_dhcp_start"]) msg["dhcp"]["limit"] = int(data["guest_dhcp_limit"]) msg["dhcp"]["lease_time"] = int(data["guest_dhcp_leasetime"]) * 60 * 60 if data["guest_qos_enabled"]: msg["qos"]["download"] = int(data["guest_qos_download"]) msg["qos"]["upload"] = int(data["guest_qos_upload"]) else: msg = {"enabled": False} res = current_state.backend.perform("guest", "update_settings", msg) return "save_result", res # store {"result": ...} to be used later... guest_form.add_callback(guest_form_cb) return guest_form
def get_form(self): data = current_state.backend.perform("router_notifications", "get_settings") data["enable_smtp"] = data["emails"]["enabled"] data["use_turris_smtp"] = "1" if data["emails"][ "smtp_type"] == "turris" else "0" data["to"] = " ".join(data["emails"]["common"]["to"]) data["sender_name"] = data["emails"]["smtp_turris"]["sender_name"] data["severity"] = data["emails"]["common"]["severity_filter"] data["news"] = data["emails"]["common"]["send_news"] data["from"] = data["emails"]["smtp_custom"]["from"] data["server"] = data["emails"]["smtp_custom"]["host"] data["port"] = data["emails"]["smtp_custom"]["port"] data["security"] = data["emails"]["smtp_custom"]["security"] data["username"] = data["emails"]["smtp_custom"]["username"] data["password"] = data["emails"]["smtp_custom"]["password"] data["delay"] = str(data["reboots"]["delay"]) data["reboot_time"] = data["reboots"]["time"] if self.data: # Update from post data.update(self.data) notifications_form = fapi.ForisForm("notifications", data) notifications = notifications_form.add_section( name="notifications", title=_("Notifications settings")) # notifications settings notifications.add_field(Checkbox, name="enable_smtp", label=_("Enable notifications"), default=False) notifications.add_field( Radio, name="use_turris_smtp", label=_("SMTP provider"), default="0", args=(("1", _("Turris")), ("0", _("Custom"))), hint= _('If you set SMTP provider to "Turris", the servers provided to members of the ' "Turris project would be used. These servers do not require any additional " 'settings. If you want to set your own SMTP server, please select "Custom" ' "and enter required settings."), ).requires("enable_smtp", True) notifications.add_field( Textbox, name="to", label=_("Recipient's email"), hint= _("Email address of recipient. Separate multiple addresses by spaces." ), required=True, validators=[ validators.RegExp( _("Doesn't contain a list of emails separated by spaces"), r"^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+ *)( +[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+ *)*$", ) ], ).requires("enable_smtp", True) # sender's name for CZ.NIC SMTP only notifications.add_field( Textbox, name="sender_name", label=_("Sender's name"), hint=_("Name of the sender - will be used as a part of the " 'sender\'s email address before the "at" sign.'), validators=[ validators.RegExp( _("Sender's name can contain only alphanumeric characters, dots " "and underscores."), r"^[0-9a-zA-Z_\.-]+$", ) ], required=True, ).requires("enable_smtp", True).requires("use_turris_smtp", "1") SEVERITY_OPTIONS = ( (1, _("Reboot is required")), (2, _("Reboot or attention is required")), (3, _("Reboot or attention is required or update was installed")), ) notifications.add_field(Dropdown, name="severity", label=_("Importance"), args=SEVERITY_OPTIONS, default=1).requires("enable_smtp", True) notifications.add_field( Checkbox, name="news", label=_("Send news"), hint=_("Send emails about new features."), default=True, ).requires("enable_smtp", True) # SMTP settings (custom server) smtp = notifications_form.add_section(name="smtp", title=_("SMTP settings")) smtp.add_field( Email, name="from", label=_("Sender address (From)"), hint=_("This is the address notifications are send from."), required=True, placeholder="*****@*****.**", ).requires("enable_smtp", True).requires("use_turris_smtp", "0") smtp.add_field(Textbox, name="server", label=_("Server address"), placeholder="example.com").requires( "enable_smtp", True).requires("use_turris_smtp", "0") smtp.add_field( Number, name="port", label=_("Server port"), validators=[validators.PositiveInteger()], required=True, ).requires("enable_smtp", True).requires("use_turris_smtp", "0") SECURITY_OPTIONS = (("none", _("None")), ("ssl", _("SSL/TLS")), ("starttls", _("STARTTLS"))) smtp.add_field(Dropdown, name="security", label=_("Security"), args=SECURITY_OPTIONS, default="none").requires("enable_smtp", True).requires( "use_turris_smtp", "0") smtp.add_field(Textbox, name="username", label=_("Username")).requires( "enable_smtp", True).requires("use_turris_smtp", "0") smtp.add_field(Password, name="password", label=_("Password")).requires( "enable_smtp", True).requires("use_turris_smtp", "0") # reboot time reboot = notifications_form.add_section( name="reboot", title=_("Automatic restarts after software update")) reboot.add_field( Number, name="delay", label=_("Delay (days)"), hint=_( "Number of days that must pass between receiving the request " "for restart and the automatic restart itself."), validators=[ validators.PositiveInteger(), validators.InRange(0, 10) ], required=True, ) reboot.add_field( Time, name="reboot_time", label=_("Reboot time"), hint=_("Time of day of automatic reboot in HH:MM format."), validators=[validators.Time()], required=True, ) def notifications_form_cb(data): msg = { "reboots": { "delay": int(data["delay"]), "time": data["reboot_time"] }, "emails": { "enabled": data["enable_smtp"] }, } if data["enable_smtp"]: msg["emails"]["smtp_type"] = ( "turris" if data["use_turris_smtp"] == "1" else "custom") msg["emails"]["common"] = { "to": [e for e in data["to"].split(" ") if e], "severity_filter": int(data["severity"]), "send_news": data["news"], } if msg["emails"]["smtp_type"] == "turris": msg["emails"]["smtp_turris"] = { "sender_name": data["sender_name"] } elif msg["emails"]["smtp_type"] == "custom": msg["emails"]["smtp_custom"] = { "from": data["from"], "host": data["server"], "port": int(data["port"]), "security": data["security"], "username": data["username"], "password": data["password"], } res = current_state.backend.perform("router_notifications", "update_settings", msg) return "save_result", res # store {"result": ...} to be used later... notifications_form.add_callback(notifications_form_cb) return notifications_form
def get_form(self): def approval_preproc_approve_status(nuci_config): """Preprocess approval status """ # try to obtain status from the form data if self.data and "approval_status" in self.data: return self.data["approval_status"] need_item = nuci_config.find_child("uci.updater.approvals.need") if not need_item: return UpdaterAutoUpdatesHandler.APPROVAL_NO if not parse_uci_bool(need_item.value): return UpdaterAutoUpdatesHandler.APPROVAL_NO seconds_item = nuci_config.find_child( "uci.updater.approvals.auto_grant_seconds") if not seconds_item: return UpdaterAutoUpdatesHandler.APPROVAL_NEEDED try: hours = int(seconds_item.value) except ValueError: return UpdaterAutoUpdatesHandler.APPROVAL_NEEDED if hours < 0: return UpdaterAutoUpdatesHandler.APPROVAL_NEEDED return UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT form = fapi.ForisForm("updater_eula", self.data, filter=filters.create_config_filter( "updater", "foris")) main_section = form.add_section(name="agree_eula", title=_(self.userfriendly_title)) main_section.add_field( Radio, name="agreed", label=_("I agree"), default="1", args=(("1", _("Use automatic updates (recommended)")), ("0", _("Turn automatic updates off"))), nuci_preproc=lambda x: "1" if preproc_disabled_to_agreed(x) else "0") approval_section = form.add_section(name="approvals", title=_("Update approvals")) main_section.add_section(approval_section) approval_section.add_field( RadioSingle, name=UpdaterAutoUpdatesHandler.APPROVAL_NO, group="approval_status", label=_("Automatic installation"), hint=_("Updates will be installed without user's intervention."), nuci_preproc=lambda e: approval_preproc_approve_status(e), ).requires("agreed", "1") approval_section.add_field( RadioSingle, name=UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT, group="approval_status", label=_("Delayed updates"), hint= _("Updates will be installed with an adjustable delay. You can also approve them manually." ), nuci_preproc=lambda e: approval_preproc_approve_status(e), ).requires("agreed", "1") approval_section.add_field( Number, name="approval_timeout", nuci_path="uci.updater.approvals.auto_grant_seconds", nuci_preproc=lambda val: int(val.value) / 60 / 60, # seconds to hours validators=[validators.InRange(1, 24 * 7)], default=24, required=True, min=1, max=24 * 7, ).requires(UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT, UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT).requires( UpdaterAutoUpdatesHandler.APPROVAL_NO, UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT).requires( UpdaterAutoUpdatesHandler.APPROVAL_NEEDED, UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT) approval_section.add_field( RadioSingle, name=UpdaterAutoUpdatesHandler.APPROVAL_NEEDED, group="approval_status", label=_("Update approval needed"), hint= _("You have to approve the updates, otherwise they won't be installed." ), nuci_preproc=lambda e: approval_preproc_approve_status(e), ).requires("agreed", "1") def form_cb(data): agreed = bool(int(data.get("agreed", "0"))) approval_status = data.get(UpdaterAutoUpdatesHandler.APPROVAL_NO, UpdaterAutoUpdatesHandler.APPROVAL_NO) auto_grant_seconds = int(data.get("approval_timeout", 24)) * 60 * 60 uci = Uci() updater = uci.add(Config("updater")) override = updater.add(Section("override", "override")) override.add(Option("disable", not agreed)) approvals = updater.add_replace(Section("approvals", "approvals")) if approval_status == UpdaterAutoUpdatesHandler.APPROVAL_NO: approvals.add(Option("need", "0")) elif approval_status == UpdaterAutoUpdatesHandler.APPROVAL_NEEDED: approvals.add(Option("need", "1")) elif approval_status == UpdaterAutoUpdatesHandler.APPROVAL_TIMEOUT: approvals.add(Option("need", "1")) approvals.add(Option("auto_grant_seconds", auto_grant_seconds)) return "edit_config", uci def save_result_cb(data): return "save_result", { 'agreed': bool(int(data.get("agreed", "0"))) } form.add_callback(form_cb) form.add_callback(save_result_cb) return form